@wrongstack/tools 0.313.0 → 0.316.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.
Files changed (182) hide show
  1. package/dist/_edit-match.d.ts +3 -2
  2. package/dist/_output-spool.d.ts +4 -3
  3. package/dist/_shell-pick.d.ts +2 -1
  4. package/dist/_spawn-stream.d.ts +2 -1
  5. package/dist/_syntax-check.d.ts +2 -1
  6. package/dist/audit.js +10 -4055
  7. package/dist/bash-kill-guard.d.ts +3 -6
  8. package/dist/bash.js +9 -2308
  9. package/dist/batch-tool-use.js +2 -187
  10. package/dist/browser/index.js +25 -1339
  11. package/dist/browser/network-guard-proxy.d.ts +2 -1
  12. package/dist/builtin.js +69 -33949
  13. package/dist/chunk-22B7GE5T.js +260 -0
  14. package/dist/chunk-2VSZC6QM.js +113 -0
  15. package/dist/chunk-3PVYQFRQ.js +472 -0
  16. package/dist/chunk-42BHI7TN.js +337 -0
  17. package/dist/chunk-4BHUSMNL.js +104 -0
  18. package/dist/chunk-4I4LWFOO.js +431 -0
  19. package/dist/chunk-4UESMQDP.js +122 -0
  20. package/dist/chunk-553IQUMO.js +478 -0
  21. package/dist/chunk-5H4GSJAI.js +223 -0
  22. package/dist/chunk-6RNIFLG4.js +305 -0
  23. package/dist/chunk-7EY5DCRO.js +434 -0
  24. package/dist/chunk-A6BRWIXN.js +317 -0
  25. package/dist/chunk-AHHDWNXC.js +200 -0
  26. package/dist/chunk-BSLVR56S.js +199 -0
  27. package/dist/chunk-BTSFTGIL.js +7 -0
  28. package/dist/chunk-D33S4RQG.js +222 -0
  29. package/dist/chunk-DA4KNE2H.js +4412 -0
  30. package/dist/chunk-DR7JOQTC.js +520 -0
  31. package/dist/chunk-EEOFQDT6.js +898 -0
  32. package/dist/chunk-EJWSCQ6D.js +137 -0
  33. package/dist/chunk-EMRGN4KM.js +170 -0
  34. package/dist/chunk-FQZOHLG3.js +89 -0
  35. package/dist/chunk-GOIZNNOA.js +221 -0
  36. package/dist/chunk-HFXSNKCV.js +196 -0
  37. package/dist/chunk-HYX2TZ7O.js +1272 -0
  38. package/dist/chunk-I64BS3VC.js +15 -0
  39. package/dist/chunk-IVWV2UM6.js +955 -0
  40. package/dist/chunk-IXMNTNW5.js +238 -0
  41. package/dist/chunk-IYK7XGDZ.js +892 -0
  42. package/dist/chunk-J5SKD6LN.js +235 -0
  43. package/dist/chunk-JNNVRHMV.js +2111 -0
  44. package/dist/chunk-JOHXDF3D.js +295 -0
  45. package/dist/chunk-JRJJX3L5.js +424 -0
  46. package/dist/chunk-K3WNSHUF.js +1371 -0
  47. package/dist/chunk-L25CVUVR.js +2830 -0
  48. package/dist/chunk-LIJQMYYX.js +59 -0
  49. package/dist/chunk-LWKUTMD5.js +197 -0
  50. package/dist/chunk-MQX2KXVW.js +54 -0
  51. package/dist/chunk-MZZN7VCD.js +359 -0
  52. package/dist/chunk-NBDZMMG2.js +169 -0
  53. package/dist/chunk-NKJW5GFO.js +366 -0
  54. package/dist/chunk-NKNOBUBU.js +522 -0
  55. package/dist/chunk-O4MBV4AX.js +134 -0
  56. package/dist/chunk-OUBDL3WH.js +3515 -0
  57. package/dist/chunk-PQKK5JH7.js +101 -0
  58. package/dist/chunk-PY2IOS7C.js +1000 -0
  59. package/dist/chunk-Q5JPPCZC.js +12 -0
  60. package/dist/chunk-QBV725YG.js +128 -0
  61. package/dist/chunk-QZQSPUBF.js +315 -0
  62. package/dist/chunk-RGISBZBD.js +231 -0
  63. package/dist/chunk-RJZQWEMS.js +84 -0
  64. package/dist/chunk-RXISBFR5.js +315 -0
  65. package/dist/chunk-S5CCLZL3.js +99 -0
  66. package/dist/chunk-SDLVH5RZ.js +178 -0
  67. package/dist/chunk-T2F4S7U4.js +1723 -0
  68. package/dist/chunk-TEBQ4VPZ.js +163 -0
  69. package/dist/chunk-U4D5S3VQ.js +21 -0
  70. package/dist/chunk-U4VAATKP.js +193 -0
  71. package/dist/chunk-UCYQTZ7F.js +113 -0
  72. package/dist/chunk-UKU2ZX4C.js +203 -0
  73. package/dist/chunk-UNSKG6DC.js +159 -0
  74. package/dist/chunk-V43EQ6VR.js +68 -0
  75. package/dist/chunk-VB3MJGCV.js +610 -0
  76. package/dist/chunk-VFKPWSOX.js +154 -0
  77. package/dist/chunk-VJNHFZ7J.js +190 -0
  78. package/dist/chunk-VXECAJJ7.js +1091 -0
  79. package/dist/chunk-WHIIIREL.js +223 -0
  80. package/dist/chunk-Z6DAKQ3U.js +1 -0
  81. package/dist/chunk-ZJQ4IGXK.js +474 -0
  82. package/dist/chunk-ZLTFLC25.js +385 -0
  83. package/dist/circuit-breaker.js +3 -191
  84. package/dist/codebase-index/ast-invariant-engine.d.ts +5 -4
  85. package/dist/codebase-index/binary-frame.d.ts +0 -2
  86. package/dist/codebase-index/bm25.d.ts +1 -1
  87. package/dist/codebase-index/circuit-breaker.d.ts +2 -1
  88. package/dist/codebase-index/codebase-ast-replace-tool.d.ts +3 -2
  89. package/dist/codebase-index/codebase-impact-analysis-tool.d.ts +4 -3
  90. package/dist/codebase-index/codebase-invariant-check-tool.d.ts +3 -2
  91. package/dist/codebase-index/codebase-repo-map-tool.d.ts +3 -2
  92. package/dist/codebase-index/codebase-skeleton-tool.d.ts +3 -2
  93. package/dist/codebase-index/codebase-targeted-test-tool.d.ts +3 -2
  94. package/dist/codebase-index/content-hash.d.ts +0 -2
  95. package/dist/codebase-index/import-extractor.d.ts +0 -13
  96. package/dist/codebase-index/index-service.d.ts +1 -1
  97. package/dist/codebase-index/index.js +84 -13688
  98. package/dist/codebase-index/languages.d.ts +2 -1
  99. package/dist/codebase-index/module-roots.d.ts +3 -2
  100. package/dist/codebase-index/parser-batch.d.ts +0 -5
  101. package/dist/codebase-index/parser-dispatch.d.ts +2 -1
  102. package/dist/codebase-index/parser-output.d.ts +4 -3
  103. package/dist/codebase-index/parser-worker-pool.d.ts +0 -2
  104. package/dist/codebase-index/parser-worker-script.d.ts +1 -16
  105. package/dist/codebase-index/parser-worker-script.js +8 -3995
  106. package/dist/codebase-index/project-server-client-state.d.ts +2 -2
  107. package/dist/codebase-index/project-server-endpoint.d.ts +0 -15
  108. package/dist/codebase-index/project-server.js +60 -8548
  109. package/dist/codebase-index/tree-sitter/visitor.d.ts +2 -1
  110. package/dist/codebase-index/tree-sitter-parser.d.ts +0 -2
  111. package/dist/codebase-index/ts-parser.d.ts +1 -1
  112. package/dist/codebase-index/vector-search.d.ts +2 -1
  113. package/dist/codebase-index/wal-maintenance.d.ts +3 -2
  114. package/dist/codebase-index/worker.js +20 -8416
  115. package/dist/codebase-index/writer-admin.d.ts +0 -1
  116. package/dist/codebase-index/writer-search.d.ts +0 -9
  117. package/dist/design.js +2 -299
  118. package/dist/diff.js +4 -256
  119. package/dist/document.js +4 -222
  120. package/dist/e2e.js +5 -476
  121. package/dist/edit.js +14 -10200
  122. package/dist/exec.js +16 -3131
  123. package/dist/fetch.js +8 -398
  124. package/dist/format.js +10 -3750
  125. package/dist/generic-parser-VUXDIAOZ.js +13 -0
  126. package/dist/git.js +4 -380
  127. package/dist/glob.js +6 -280
  128. package/dist/go-parser-JXYKJHRC.js +469 -0
  129. package/dist/grep.js +7 -604
  130. package/dist/index.js +318 -35387
  131. package/dist/install.js +10 -4091
  132. package/dist/json-parser-IBHZ4BZC.js +213 -0
  133. package/dist/json.js +4 -665
  134. package/dist/kanban-contract-actions.d.ts +1 -1
  135. package/dist/kanban-detail-actions.d.ts +2 -1
  136. package/dist/kanban-presence.d.ts +2 -1
  137. package/dist/kanban-serializer.d.ts +0 -8
  138. package/dist/kanban-split-task-handler.d.ts +2 -2
  139. package/dist/kanban-tool-types.d.ts +2 -1
  140. package/dist/kanban.js +3 -2096
  141. package/dist/languages/diagnostics.d.ts +2 -1
  142. package/dist/languages/index.js +23 -4664
  143. package/dist/languages/legacy-bridge.d.ts +3 -2
  144. package/dist/languages/types.d.ts +2 -1
  145. package/dist/legacy-bridge-7M6QLUQN.js +18 -0
  146. package/dist/lint.js +10 -3706
  147. package/dist/logs.js +4 -287
  148. package/dist/memory.js +6 -215
  149. package/dist/mode.js +3 -99
  150. package/dist/outdated.js +4 -5170
  151. package/dist/pack.js +65 -33897
  152. package/dist/parser-dispatch-QH4XPGG6.js +14 -0
  153. package/dist/patch.js +13 -9935
  154. package/dist/plan.js +5 -3286
  155. package/dist/process-registry.js +8 -651
  156. package/dist/ps-slash.js +12 -1439
  157. package/dist/pwsh.d.ts +0 -1
  158. package/dist/py-parser-IS4HKYMF.js +16 -0
  159. package/dist/read.js +13 -9816
  160. package/dist/replace.js +15 -10014
  161. package/dist/rs-parser-XHUUO2KZ.js +81 -0
  162. package/dist/scaffold.js +4 -253
  163. package/dist/search.js +5 -585
  164. package/dist/session-kanban-sync.d.ts +0 -6
  165. package/dist/session-kanban.js +30 -972
  166. package/dist/skill.js +2 -215
  167. package/dist/spawn-background.d.ts +1 -1
  168. package/dist/task.js +5 -3410
  169. package/dist/test.js +10 -3773
  170. package/dist/todo.js +4 -2891
  171. package/dist/tool-help.js +3 -123
  172. package/dist/tool-search.js +3 -79
  173. package/dist/tool-tier.js +68 -33984
  174. package/dist/tool-use.js +2 -93
  175. package/dist/tree-sitter-parser-AIERW3YI.js +15 -0
  176. package/dist/tree.js +4 -288
  177. package/dist/ts-parser-RCTYKSVI.js +232 -0
  178. package/dist/typecheck.js +10 -3753
  179. package/dist/win32.js +6 -60
  180. package/dist/write.js +14 -9882
  181. package/dist/yaml-parser-4SAXV3PL.js +157 -0
  182. package/package.json +5 -5
@@ -1,4001 +1,14 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropNames = Object.getOwnPropertyNames;
3
- var __esm = (fn, res, err) => function __init() {
4
- if (err) throw err[0];
5
- try {
6
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
7
- } catch (e) {
8
- throw err = [e], e;
9
- }
10
- };
11
- var __export = (target, all) => {
12
- for (var name in all)
13
- __defProp(target, name, { get: all[name], enumerable: true });
14
- };
15
-
16
- // src/_win32-resolve.ts
17
- import * as fs from "node:fs";
18
- import * as path from "node:path";
19
- function resolveWin32Command(cmd) {
20
- if (process.platform !== "win32") return cmd;
21
- if (cmd.includes("/") || cmd.includes("\\") || path.extname(cmd.replace(/\//g, "\\"))) {
22
- return cmd;
23
- }
24
- const pathext = (process.env["PATHEXT"] ?? ".COM;.EXE;.BAT;.CMD;.VBS;.JS;.WS;.MSC").toLowerCase().split(";");
25
- const pathDirs = (process.env["PATH"] ?? "").split(path.delimiter);
26
- for (const dir of pathDirs) {
27
- const base = path.join(dir, cmd);
28
- for (const ext of pathext) {
29
- const full = `${base}${ext}`;
30
- try {
31
- fs.accessSync(full, fs.constants.X_OK);
32
- return full;
33
- } catch {
34
- }
35
- }
36
- }
37
- return cmd;
38
- }
39
- var init_win32_resolve = __esm({
40
- "src/_win32-resolve.ts"() {
41
- "use strict";
42
- }
43
- });
44
-
45
- // src/codebase-index/parser-output.ts
46
- function coerceSymbols(value) {
47
- if (!Array.isArray(value)) return [];
48
- return value.flatMap((entry) => {
49
- const candidate = entry;
50
- if (typeof candidate.name !== "string" || typeof candidate.kind !== "string") return [];
51
- return [
52
- {
53
- name: candidate.name,
54
- kind: candidate.kind,
55
- line: typeof candidate.line === "number" ? candidate.line : 1,
56
- col: typeof candidate.col === "number" ? candidate.col : 0,
57
- signature: typeof candidate.signature === "string" ? candidate.signature : "",
58
- scope: typeof candidate.scope === "string" ? candidate.scope : ""
59
- }
60
- ];
61
- });
62
- }
63
- function coerceRefs(value, lang) {
64
- if (!Array.isArray(value)) return [];
65
- return value.flatMap((entry) => {
66
- const candidate = entry;
67
- if (typeof candidate.toName !== "string" || !candidate.toName) return [];
68
- if (typeof candidate.callType !== "string" || !CALL_TYPES.has(candidate.callType)) return [];
69
- const module = typeof candidate.module === "string" && candidate.module ? candidate.module : void 0;
70
- return [
71
- {
72
- fromId: 0,
73
- toName: candidate.toName,
74
- callType: candidate.callType,
75
- line: typeof candidate.line === "number" ? candidate.line : 1,
76
- lang,
77
- module
78
- }
79
- ];
80
- });
81
- }
82
- function parseParserOutput(stdout, lang) {
83
- const trimmed = stdout.trim();
84
- if (!trimmed) return { symbols: [], refs: [] };
85
- let parsed;
86
- try {
87
- parsed = JSON.parse(trimmed);
88
- } catch {
89
- return { symbols: [], refs: [] };
90
- }
91
- if (Array.isArray(parsed)) return { symbols: coerceSymbols(parsed), refs: [] };
92
- const record = parsed;
93
- return {
94
- symbols: coerceSymbols(record.symbols),
95
- refs: dedupeRefs(coerceRefs(record.refs, lang))
96
- };
97
- }
98
- function parseParserBatchOutput(stdout, lang) {
99
- const trimmed = stdout.trim();
100
- if (!trimmed) return [];
101
- let parsed;
102
- try {
103
- parsed = JSON.parse(trimmed);
104
- } catch {
105
- return [];
106
- }
107
- if (!parsed || typeof parsed !== "object") return [];
108
- const results = parsed.results;
109
- if (!Array.isArray(results)) return [];
110
- return results.flatMap((entry) => {
111
- if (typeof entry !== "object" || entry === null || Array.isArray(entry)) return [];
112
- const candidate = entry;
113
- if (typeof candidate.file !== "string" || !candidate.file) return [];
114
- return [
115
- {
116
- file: candidate.file,
117
- error: typeof candidate.error === "string" && candidate.error ? candidate.error : void 0,
118
- symbols: coerceSymbols(candidate.symbols),
119
- refs: dedupeRefs(coerceRefs(candidate.refs, lang))
120
- }
121
- ];
122
- });
123
- }
124
- function dedupeRefs(refs) {
125
- const seen = /* @__PURE__ */ new Set();
126
- return refs.filter((ref) => {
127
- const key = `${ref.toName}:${ref.callType}:${ref.line}:${ref.module ?? ""}`;
128
- if (seen.has(key)) return false;
129
- seen.add(key);
130
- return true;
131
- });
132
- }
133
- var CALL_TYPES;
134
- var init_parser_output = __esm({
135
- "src/codebase-index/parser-output.ts"() {
136
- "use strict";
137
- CALL_TYPES = /* @__PURE__ */ new Set([
138
- "call",
139
- "type_ref",
140
- "inherit",
141
- "implement",
142
- "import"
143
- ]);
144
- }
145
- });
146
-
147
- // src/codebase-index/spawn-gate.ts
148
- function withSpawnGate(fn) {
149
- const run = chain.then(fn, fn);
150
- chain = run.then(
151
- () => void 0,
152
- () => void 0
153
- );
154
- return run;
155
- }
156
- var chain;
157
- var init_spawn_gate = __esm({
158
- "src/codebase-index/spawn-gate.ts"() {
159
- "use strict";
160
- chain = Promise.resolve();
161
- }
162
- });
163
-
164
- // src/codebase-index/generic-parser.ts
165
- var generic_parser_exports = {};
166
- __export(generic_parser_exports, {
167
- GENERIC_MAX_FILE_CHARS: () => GENERIC_MAX_FILE_CHARS,
168
- GENERIC_MAX_SYMBOLS_DEFAULT: () => GENERIC_MAX_SYMBOLS_DEFAULT,
169
- parseGeneric: () => parseGeneric,
170
- parseSymbols: () => parseSymbols
171
- });
172
- function patternsFor(lang) {
173
- return LANG_PATTERNS[lang] ?? LANG_PATTERNS.other ?? [];
174
- }
175
- function looksBinary(content) {
176
- if (content.includes("\0")) return true;
177
- const sample = content.slice(0, 2048);
178
- if (sample.length === 0) return false;
179
- let bad = 0;
180
- for (let i = 0; i < sample.length; i++) {
181
- const c = sample.charCodeAt(i);
182
- if (c === 9 || c === 10 || c === 13) continue;
183
- if (c < 32 || c === 127) bad++;
184
- }
185
- return bad / sample.length > 0.1;
186
- }
187
- function newlineOffsets2(content) {
188
- const offsets = [];
189
- for (let i = 0; i < content.length; i++) {
190
- if (content.charCodeAt(i) === 10) offsets.push(i);
191
- }
192
- return offsets;
193
- }
194
- function lineColAt(offsets, index) {
195
- let low = 0;
196
- let high = offsets.length;
197
- while (low < high) {
198
- const mid = low + high >>> 1;
199
- if ((offsets[mid] ?? 0) < index) low = mid + 1;
200
- else high = mid;
201
- }
202
- const lastNl = low > 0 ? offsets[low - 1] : -1;
203
- return { line: low + 1, col: index - lastNl };
204
- }
205
- function parseGeneric(opts) {
206
- const { file, lang } = opts;
207
- const maxSymbols = opts.maxSymbols ?? GENERIC_MAX_SYMBOLS_DEFAULT;
208
- const mtimeMs = Date.now();
209
- if (!opts.content || looksBinary(opts.content)) {
210
- return { file, lang, symbols: [], mtimeMs };
211
- }
212
- const content = opts.content.length > GENERIC_MAX_FILE_CHARS ? opts.content.slice(0, GENERIC_MAX_FILE_CHARS) : opts.content;
213
- const patterns = patternsFor(lang);
214
- const symbols = [];
215
- const seen = /* @__PURE__ */ new Set();
216
- const nlOffsets = newlineOffsets2(content);
217
- for (const pattern of patterns) {
218
- const re = new RegExp(
219
- pattern.re.source,
220
- pattern.re.flags.includes("g") ? pattern.re.flags : `${pattern.re.flags}g`
221
- );
222
- re.lastIndex = 0;
223
- for (const match of content.matchAll(re)) {
224
- if (symbols.length >= maxSymbols) break;
225
- let name = (match[1] ?? match[2] ?? "").trim();
226
- if (lang === "md" && match[2]) name = match[2].trim();
227
- if (!name || name.length > 200) continue;
228
- name = name.replace(/^#+\s*/, "").replace(/["'`]/g, "");
229
- if (!name || KEYWORDS.has(name.toLowerCase())) continue;
230
- if (!/^[A-Za-z_#.@/\w][\w.\-:/#!?]*$/.test(name) && lang !== "md" && lang !== "toml") {
231
- continue;
232
- }
233
- const { line, col } = lineColAt(nlOffsets, match.index ?? 0);
234
- const key = `${name}\0${line}\0${pattern.kind}`;
235
- if (seen.has(key)) continue;
236
- seen.add(key);
237
- const nl = content.indexOf("\n", match.index);
238
- const lineText = content.slice(match.index, nl === -1 ? content.length : nl);
239
- const signature = (lineText || name).trim().slice(0, 500);
240
- symbols.push({
241
- id: 0,
242
- lang,
243
- kind: lang === "md" ? "namespace" : pattern.kind,
244
- name: name.slice(0, 200),
245
- file,
246
- line,
247
- col,
248
- signature,
249
- docComment: "",
250
- scope: "",
251
- text: `${name} ${signature}`.trim().slice(0, 1e3)
252
- });
253
- }
254
- if (symbols.length >= maxSymbols) break;
255
- }
256
- return { file, lang, symbols, mtimeMs };
257
- }
258
- async function parseSymbols(opts) {
259
- return parseGeneric(opts);
260
- }
261
- var C_LIKE, LANG_PATTERNS, KEYWORDS, GENERIC_MAX_SYMBOLS_DEFAULT, GENERIC_MAX_FILE_CHARS;
262
- var init_generic_parser = __esm({
263
- "src/codebase-index/generic-parser.ts"() {
264
- "use strict";
265
- C_LIKE = [
266
- { re: /\b(?:class|struct|enum|interface|union)\s+([A-Za-z_]\w*)/g, kind: "class" },
267
- {
268
- re: /\b(?:public|private|protected|static|final|async|override|virtual|inline|export)?\s*(?:[\w:<>[\]\s*&]+)\s+([A-Za-z_]\w*)\s*\([^;{]*\)\s*(?:const)?\s*[{;]/g,
269
- kind: "function"
270
- },
271
- { re: /\b(?:namespace)\s+([A-Za-z_]\w*)/g, kind: "namespace" }
272
- ];
273
- LANG_PATTERNS = {
274
- py: [
275
- { re: /^(?:async\s+)?def\s+([A-Za-z_]\w*)/gm, kind: "function" },
276
- { re: /^class\s+([A-Za-z_]\w*)/gm, kind: "class" },
277
- { re: /^([A-Za-z_]\w*)\s*=/gm, kind: "var" }
278
- ],
279
- go: [
280
- { re: /^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)\s*\(/gm, kind: "function" },
281
- { re: /^type\s+([A-Za-z_]\w*)\b/gm, kind: "type" },
282
- { re: /^(?:const|var)\s+([A-Za-z_]\w*)\b/gm, kind: "const" },
283
- { re: /^package\s+([A-Za-z_]\w*)/gm, kind: "namespace" }
284
- ],
285
- rs: [
286
- { re: /\bfn\s+([A-Za-z_]\w*)/g, kind: "function" },
287
- { re: /\bstruct\s+([A-Za-z_]\w*)/g, kind: "struct" },
288
- { re: /\benum\s+([A-Za-z_]\w*)/g, kind: "enum" },
289
- { re: /\btrait\s+([A-Za-z_]\w*)/g, kind: "trait" },
290
- { re: /\bimpl(?:\s*<[^>]+>)?\s+([A-Za-z_]\w*)/g, kind: "impl" },
291
- { re: /\b(?:const|static)\s+([A-Za-z_]\w*)/g, kind: "const" },
292
- { re: /\bmod\s+([A-Za-z_]\w*)/g, kind: "mod" }
293
- ],
294
- c: C_LIKE,
295
- cpp: C_LIKE,
296
- java: [
297
- { re: /\b(?:class|interface|enum|record)\s+([A-Za-z_]\w*)/g, kind: "class" },
298
- {
299
- re: /\b(?:public|private|protected|static|final|abstract|synchronized|native|default|\s)+\s*[\w.<>,[\]\s]+\s+([A-Za-z_]\w*)\s*\(/g,
300
- kind: "method"
301
- }
302
- ],
303
- csharp: [
304
- { re: /\b(?:class|interface|struct|enum|record)\s+([A-Za-z_]\w*)/g, kind: "class" },
305
- { re: /\bnamespace\s+([A-Za-z_.\w]+)/g, kind: "namespace" },
306
- {
307
- re: /\b(?:public|private|protected|internal|static|async|override|virtual|\s)+\s*[\w.<>,[\]\s]+\s+([A-Za-z_]\w*)\s*\(/g,
308
- kind: "method"
309
- }
310
- ],
311
- php: [
312
- { re: /\bfunction\s+([A-Za-z_]\w*)/g, kind: "function" },
313
- { re: /\bclass\s+([A-Za-z_]\w*)/g, kind: "class" },
314
- { re: /\binterface\s+([A-Za-z_]\w*)/g, kind: "interface" },
315
- { re: /\bnamespace\s+([A-Za-z_\\]+)/g, kind: "namespace" }
316
- ],
317
- ruby: [
318
- { re: /^\s*def\s+(?:self\.)?([A-Za-z_]\w*[!?]?)/gm, kind: "function" },
319
- { re: /^\s*class\s+([A-Za-z_]\w*)/gm, kind: "class" },
320
- { re: /^\s*module\s+([A-Za-z_]\w*)/gm, kind: "namespace" }
321
- ],
322
- swift: [
323
- { re: /\b(?:func)\s+([A-Za-z_]\w*)/g, kind: "function" },
324
- { re: /\b(?:class|struct|enum|protocol|actor)\s+([A-Za-z_]\w*)/g, kind: "class" }
325
- ],
326
- kotlin: [
327
- { re: /\b(?:fun)\s+([A-Za-z_]\w*)/g, kind: "function" },
328
- {
329
- re: /\b(?:class|interface|object|enum\s+class|data\s+class)\s+([A-Za-z_]\w*)/g,
330
- kind: "class"
331
- }
332
- ],
333
- scala: [
334
- { re: /\b(?:def)\s+([A-Za-z_]\w*)/g, kind: "function" },
335
- { re: /\b(?:class|object|trait|enum)\s+([A-Za-z_]\w*)/g, kind: "class" }
336
- ],
337
- shell: [
338
- { re: /^(?:function\s+)?([A-Za-z_]\w*)\s*\(\)\s*\{/gm, kind: "function" },
339
- { re: /^([A-Za-z_][\w]*)\s*\(\)\s*\{/gm, kind: "function" }
340
- ],
341
- sql: [
342
- {
343
- re: /\bCREATE\s+(?:OR\s+REPLACE\s+)?(?:TABLE|VIEW|INDEX|FUNCTION|PROCEDURE|TRIGGER)\s+(?:IF\s+NOT\s+EXISTS\s+)?([A-Za-z_"][\w."]*)/gi,
344
- kind: "type"
345
- }
346
- ],
347
- md: [{ re: /^(#{1,6})\s+(.+)$/gm, kind: "namespace" }],
348
- toml: [{ re: /^\[([^\]]+)\]/gm, kind: "namespace" }],
349
- html: [
350
- { re: /\bid\s*=\s*["']([^"']+)["']/gi, kind: "property" },
351
- { re: /<(?:script|template|style)\b/gi, kind: "namespace" }
352
- ],
353
- css: [
354
- { re: /^\s*([.#]?[A-Za-z_][\w-]*)\s*\{/gm, kind: "type" },
355
- { re: /@(?:keyframes|media|supports)\s+([^{\s]+)/g, kind: "namespace" }
356
- ],
357
- vue: [
358
- {
359
- re: /\b(?:function|const|let|var|class|export\s+(?:default\s+)?(?:function|class|const))\s+([A-Za-z_]\w*)/g,
360
- kind: "function"
361
- },
362
- { re: /<(?:script|template|style)\b/gi, kind: "namespace" }
363
- ],
364
- svelte: [
365
- {
366
- re: /\b(?:function|const|let|var|class|export\s+(?:default\s+)?(?:function|class|const))\s+([A-Za-z_]\w*)/g,
367
- kind: "function"
368
- }
369
- ],
370
- dart: [
371
- { re: /\b(?:class|enum|mixin|extension)\s+([A-Za-z_]\w*)/g, kind: "class" },
372
- { re: /\b([A-Za-z_]\w*)\s*\([^;]*\)\s*(?:async\s*)?\{/g, kind: "function" }
373
- ],
374
- lua: [
375
- { re: /\bfunction\s+([A-Za-z_.:]\w*)/g, kind: "function" },
376
- { re: /\blocal\s+function\s+([A-Za-z_]\w*)/g, kind: "function" }
377
- ],
378
- r: [
379
- { re: /([A-Za-z.]\w*)\s*<-\s*function\s*\(/g, kind: "function" },
380
- { re: /([A-Za-z.]\w*)\s*=\s*function\s*\(/g, kind: "function" }
381
- ],
382
- proto: [
383
- { re: /\b(?:message|service|enum)\s+([A-Za-z_]\w*)/g, kind: "type" },
384
- { re: /\brpc\s+([A-Za-z_]\w*)/g, kind: "function" }
385
- ],
386
- graphql: [
387
- { re: /\b(?:type|interface|enum|input|union|scalar)\s+([A-Za-z_]\w*)/g, kind: "type" },
388
- { re: /\b(?:query|mutation|subscription)\s+([A-Za-z_]\w*)/g, kind: "function" }
389
- ],
390
- zig: [
391
- { re: /\b(?:fn|pub\s+fn)\s+([A-Za-z_]\w*)/g, kind: "function" },
392
- { re: /\b(?:const|var)\s+([A-Za-z_]\w*)/g, kind: "const" },
393
- { re: /\b(?:struct|enum|union)\s*\{/g, kind: "type" }
394
- ],
395
- elixir: [
396
- { re: /\bdef(?:p|macro|macrop)?\s+([A-Za-z_]\w*[!?]?)/g, kind: "function" },
397
- // Dotted module names must be captured whole: `alias Foo.Bar` resolves
398
- // against this symbol, and a `Foo`-only capture never matches it.
399
- { re: /\bdefmodule\s+([A-Z][\w.]*)/g, kind: "namespace" }
400
- ],
401
- haskell: [
402
- // Target of `import Data.List`.
403
- { re: /^module\s+([A-Z][\w.]*)/gm, kind: "namespace" },
404
- { re: /^([A-Za-z_]\w*)\s*::/gm, kind: "function" },
405
- { re: /\bdata\s+([A-Za-z_]\w*)/g, kind: "type" },
406
- { re: /\btype\s+(?:family\s+)?([A-Za-z_]\w*)/g, kind: "type" },
407
- { re: /\bclass\s+([A-Za-z_]\w*)/g, kind: "class" }
408
- ],
409
- other: [
410
- { re: /^(?:export\s+)?(?:async\s+)?function\s+([A-Za-z_]\w*)/gm, kind: "function" },
411
- { re: /^(?:export\s+)?class\s+([A-Za-z_]\w*)/gm, kind: "class" },
412
- { re: /^(?:export\s+)?(?:const|let|var)\s+([A-Za-z_]\w*)/gm, kind: "const" },
413
- { re: /^(?:async\s+)?def\s+([A-Za-z_]\w*)/gm, kind: "function" },
414
- { re: /^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)/gm, kind: "function" },
415
- { re: /\bfn\s+([A-Za-z_]\w*)/g, kind: "function" },
416
- { re: /^(?:target|PHONY)\s*:/gm, kind: "namespace" }
417
- ]
418
- };
419
- KEYWORDS = /* @__PURE__ */ new Set([
420
- "if",
421
- "else",
422
- "for",
423
- "while",
424
- "switch",
425
- "case",
426
- "return",
427
- "break",
428
- "continue",
429
- "new",
430
- "delete",
431
- "typeof",
432
- "instanceof",
433
- "void",
434
- "null",
435
- "true",
436
- "false",
437
- "this",
438
- "super",
439
- "import",
440
- "export",
441
- "from",
442
- "as",
443
- "default",
444
- "public",
445
- "private",
446
- "protected",
447
- "static",
448
- "final",
449
- "class",
450
- "struct",
451
- "enum",
452
- "interface",
453
- "function",
454
- "def",
455
- "fn",
456
- "func",
457
- "var",
458
- "let",
459
- "const",
460
- "package",
461
- "namespace",
462
- "module",
463
- "using",
464
- "include",
465
- "require",
466
- "select",
467
- "from",
468
- "where",
469
- "and",
470
- "or",
471
- "not",
472
- "in",
473
- "is",
474
- "try",
475
- "catch",
476
- "finally",
477
- "throw",
478
- "async",
479
- "await",
480
- "yield"
481
- ]);
482
- GENERIC_MAX_SYMBOLS_DEFAULT = 500;
483
- GENERIC_MAX_FILE_CHARS = 512 * 1024;
484
- }
485
- });
486
-
487
- // src/codebase-index/languages.ts
488
- import * as path3 from "node:path";
489
- function detectLang(file) {
490
- const base = path3.basename(file);
491
- const lowerBase = base.toLowerCase();
492
- if (lowerBase.endsWith(".d.ts") || lowerBase.endsWith(".d.mts") || lowerBase.endsWith(".d.cts")) {
493
- return "ts";
494
- }
495
- const special = SPECIAL_FILENAMES[lowerBase];
496
- if (special) return special;
497
- const ext = path3.extname(base).toLowerCase();
498
- if (!ext) return null;
499
- return EXT_TO_LANG[ext] ?? null;
500
- }
501
- var EXT_TO_LANG, INDEXABLE_EXTENSIONS, SPECIAL_FILENAMES, LANG_FAMILY, LANG_FAMILY_ENTRIES;
502
- var init_languages = __esm({
503
- "src/codebase-index/languages.ts"() {
504
- "use strict";
505
- EXT_TO_LANG = {
506
- // TypeScript / JavaScript (first-class TS compiler API)
507
- ".ts": "ts",
508
- ".mts": "ts",
509
- ".cts": "ts",
510
- ".tsx": "tsx",
511
- ".js": "js",
512
- ".mjs": "js",
513
- ".cjs": "js",
514
- ".jsx": "jsx",
515
- // First-class native/spawn parsers (+ regex fallback)
516
- ".go": "go",
517
- ".py": "py",
518
- ".pyi": "py",
519
- ".pyw": "py",
520
- ".rs": "rs",
521
- ".json": "json",
522
- ".jsonc": "json",
523
- ".yaml": "yaml",
524
- ".yml": "yaml",
525
- // C family
526
- ".c": "c",
527
- ".h": "c",
528
- ".cc": "cpp",
529
- ".cpp": "cpp",
530
- ".cxx": "cpp",
531
- ".hh": "cpp",
532
- ".hpp": "cpp",
533
- ".hxx": "cpp",
534
- // JVM / .NET
535
- ".java": "java",
536
- ".cs": "csharp",
537
- ".kt": "kotlin",
538
- ".kts": "kotlin",
539
- ".scala": "scala",
540
- ".sc": "scala",
541
- // Scripting
542
- ".php": "php",
543
- ".rb": "ruby",
544
- ".swift": "swift",
545
- ".dart": "dart",
546
- ".lua": "lua",
547
- ".r": "r",
548
- ".R": "r",
549
- ".pl": "other",
550
- ".pm": "other",
551
- // Systems / functional
552
- ".zig": "zig",
553
- ".ex": "elixir",
554
- ".exs": "elixir",
555
- ".hs": "haskell",
556
- ".lhs": "haskell",
557
- // Shell / data / docs / web
558
- ".sh": "shell",
559
- ".bash": "shell",
560
- ".zsh": "shell",
561
- ".ps1": "shell",
562
- ".sql": "sql",
563
- ".md": "md",
564
- ".mdx": "md",
565
- ".toml": "toml",
566
- ".html": "html",
567
- ".htm": "html",
568
- ".css": "css",
569
- ".scss": "css",
570
- ".less": "css",
571
- ".vue": "vue",
572
- ".svelte": "svelte",
573
- ".proto": "proto",
574
- ".graphql": "graphql",
575
- ".gql": "graphql"
576
- };
577
- INDEXABLE_EXTENSIONS = Object.freeze(
578
- [...new Set(Object.keys(EXT_TO_LANG).map((e) => e.toLowerCase()))].sort()
579
- );
580
- SPECIAL_FILENAMES = {
581
- makefile: "other",
582
- gnumakefile: "other",
583
- dockerfile: "other",
584
- "docker-compose.yml": "yaml",
585
- "docker-compose.yaml": "yaml",
586
- "cmakelists.txt": "other",
587
- gemfile: "ruby",
588
- rakefile: "ruby",
589
- procfile: "other",
590
- justfile: "other"
591
- };
592
- LANG_FAMILY = {
593
- // Single-compilation-unit family: a .vue/.svelte script block is JS/TS and
594
- // imports from — and is imported by — plain .ts files.
595
- ts: "js",
596
- tsx: "js",
597
- js: "js",
598
- jsx: "js",
599
- vue: "js",
600
- svelte: "js",
601
- go: "go",
602
- py: "py",
603
- rs: "rs",
604
- // The JVM resolves across languages: Kotlin and Scala call Java directly.
605
- java: "jvm",
606
- kotlin: "jvm",
607
- scala: "jvm",
608
- csharp: "dotnet",
609
- // A .h header is consumed by both C and C++ translation units.
610
- c: "c",
611
- cpp: "c",
612
- ruby: "ruby",
613
- php: "php",
614
- swift: "swift",
615
- dart: "dart",
616
- elixir: "elixir",
617
- haskell: "haskell",
618
- zig: "zig",
619
- lua: "lua",
620
- r: "r",
621
- shell: "shell",
622
- sql: "sql",
623
- json: "data",
624
- yaml: "data",
625
- toml: "data",
626
- html: "web",
627
- css: "web",
628
- proto: "proto",
629
- graphql: "graphql",
630
- md: "other",
631
- other: "other"
632
- };
633
- LANG_FAMILY_ENTRIES = Object.freeze(
634
- Object.entries(LANG_FAMILY).map(
635
- ([lang, family]) => Object.freeze([lang, family])
636
- )
637
- );
638
- }
639
- });
640
-
641
- // src/codebase-index/py-parser.ts
642
- var py_parser_exports = {};
643
- __export(py_parser_exports, {
644
- detectLang: () => detectLang,
645
- parseSymbols: () => parseSymbols2,
646
- resolvePythonBinary: () => resolvePythonBinary
647
- });
648
- import { spawn as spawn2 } from "node:child_process";
649
- import * as fs3 from "node:fs/promises";
650
- import * as os2 from "node:os";
651
- import * as path4 from "node:path";
652
- async function parseSymbols2(opts) {
653
- const { file, content, lang } = opts;
654
- try {
655
- const native = await withSpawnGate(() => syncPyParse(file, content, lang));
656
- if (native !== null) return native;
657
- } catch {
658
- }
659
- return parseGeneric({ file, content, lang: lang === "py" ? "py" : lang });
660
- }
661
- async function resolvePython() {
662
- const candidates = process.platform === "win32" ? ["python3", "python", "py"] : ["python3", "python"];
663
- for (const name of candidates) {
664
- const resolved = resolveWin32Command(name);
665
- if (!await commandIsAvailable(resolved)) continue;
666
- return resolved;
667
- }
668
- return null;
669
- }
670
- function commandIsAvailable(command) {
671
- return new Promise((resolve) => {
672
- let settled = false;
673
- const proc = spawn2(command, ["--version"], {
674
- stdio: "ignore",
675
- windowsHide: true
676
- });
677
- const finish = (available) => {
678
- if (settled) return;
679
- settled = true;
680
- clearTimeout(timer);
681
- resolve(available);
682
- };
683
- const timer = setTimeout(() => {
684
- proc.kill("SIGKILL");
685
- finish(false);
686
- }, 5e3);
687
- timer.unref?.();
688
- proc.once("error", () => finish(false));
689
- proc.once("close", (code) => finish(code === 0));
690
- });
691
- }
692
- function spawnPyParser(pyBinary, scriptPath, filePath, content) {
693
- return new Promise((resolve, reject) => {
694
- let settled = false;
695
- const proc = spawn2(pyBinary, [scriptPath, filePath], {
696
- stdio: ["pipe", "pipe", "pipe"],
697
- windowsHide: true
698
- });
699
- proc.on("error", (err) => {
700
- if (settled) return;
701
- settled = true;
702
- reject(err);
703
- });
704
- proc.stdin?.write(content);
705
- proc.stdin?.end();
706
- let stdout = "";
707
- proc.stdout?.on("data", (chunk) => {
708
- stdout += chunk.toString();
709
- });
710
- proc.stderr?.resume();
711
- const timer = setTimeout(() => {
712
- if (settled) return;
713
- settled = true;
714
- proc.kill("SIGKILL");
715
- reject(new Error("timeout"));
716
- }, 15e3);
717
- timer.unref?.();
718
- proc.on("close", (code) => {
719
- if (settled) return;
720
- settled = true;
721
- clearTimeout(timer);
722
- resolve({ code, stdout });
723
- });
724
- });
725
- }
726
- function resolvePythonBinary() {
727
- cachedPyBinary ??= resolvePython();
728
- return cachedPyBinary;
729
- }
730
- async function syncPyParse(filePath, content, lang) {
731
- try {
732
- if (!_cachedScriptPath) {
733
- const tmpDir = path4.join(os2.tmpdir(), "ws-py-parse");
734
- await fs3.mkdir(tmpDir, { recursive: true });
735
- _cachedScriptPath = path4.join(tmpDir, "parse.py");
736
- await fs3.writeFile(_cachedScriptPath, PY_PARSE_SCRIPT, "utf8");
737
- }
738
- cachedPyBinary ??= resolvePython();
739
- const pyBinary = await cachedPyBinary;
740
- if (!pyBinary) return null;
741
- const { code, stdout } = await spawnPyParser(pyBinary, _cachedScriptPath, filePath, content);
742
- if (code !== 0 || !stdout.trim()) {
743
- return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
744
- }
745
- const { symbols: raw, refs } = parseParserOutput(stdout, lang);
746
- const symbols = raw.map((s) => ({
747
- id: 0,
748
- lang,
749
- kind: s.kind,
750
- name: s.name,
751
- file: filePath,
752
- line: s.line,
753
- col: s.col,
754
- signature: s.signature ?? "",
755
- docComment: "",
756
- scope: s.scope ?? "",
757
- text: `${s.name} ${s.signature ?? ""}`.trim()
758
- }));
759
- return { file: filePath, lang, symbols, refs, mtimeMs: Date.now() };
760
- } catch {
761
- return null;
762
- }
763
- }
764
- var PY_PARSE_SCRIPT, _cachedScriptPath, cachedPyBinary;
765
- var init_py_parser = __esm({
766
- "src/codebase-index/py-parser.ts"() {
767
- "use strict";
768
- init_win32_resolve();
769
- init_generic_parser();
770
- init_parser_output();
771
- init_spawn_gate();
772
- init_languages();
773
- PY_PARSE_SCRIPT = `import ast, json, sys, os
774
-
775
- def get_name(node):
776
- if isinstance(node, ast.Name):
777
- return node.id
778
- elif isinstance(node, ast.Attribute):
779
- return get_name(node.value) + "." + node.attr
780
- elif isinstance(node, ast.Subscript):
781
- return get_name(node.value)
782
- elif isinstance(node, ast.Call):
783
- return get_name(node.func)
784
- elif isinstance(node, ast.Constant):
785
- return str(node.value)
786
- return ""
787
-
788
- def get_decorators(node):
789
- decs = []
790
- for dec in node.decorator_list:
791
- decs.append(get_name(dec))
792
- return decs
793
-
794
- def get_bases(node):
795
- bases = []
796
- for base in node.bases:
797
- bases.append(get_name(base))
798
- return bases
799
-
800
- def get_args(args):
801
- parts = []
802
- for arg in args.args:
803
- parts.append(arg.arg)
804
- return ", ".join(parts)
805
-
806
- def get_returns(node):
807
- if node.returns is None:
808
- return ""
809
- return get_name(node.returns)
810
-
811
- class Sym:
812
- def __init__(self, name, kind, line, col, signature, scope):
813
- self.name = name
814
- self.kind = kind
815
- self.line = line
816
- self.col = col
817
- self.signature = signature
818
- self.scope = scope
819
- def to_dict(self):
820
- return {
821
- "name": self.name,
822
- "kind": self.kind,
823
- "line": self.line,
824
- "col": self.col,
825
- "signature": self.signature,
826
- "scope": self.scope,
827
- }
828
-
829
- def is_private(name):
830
- return name.startswith("__") and not name.endswith("__")
831
-
832
- def leaf_name(node):
833
- # Declared name of the callee: \`join\` of \`os.path.join\`. Matches how the
834
- # TypeScript and Go extractors record call refs, so resolution behaves the
835
- # same across languages.
836
- if isinstance(node, ast.Attribute):
837
- return node.attr
838
- if isinstance(node, ast.Name):
839
- return node.id
840
- return get_name(node).split(".")[-1]
841
-
842
- syms = []
843
- refs = []
844
- errors = []
845
-
846
- try:
847
- source = sys.stdin.read()
848
- tree = ast.parse(source, filename=sys.argv[1])
849
- except Exception as e:
850
- errors.append(str(e))
851
- print(json.dumps({"symbols": [], "refs": []}))
852
- sys.exit(0)
853
-
854
- # Module-level scope
855
- module_scope = os.path.basename(sys.argv[1])[:-3] # strip .py
856
-
857
- class ModuleVisitor(ast.NodeVisitor):
858
- def __init__(self):
859
- self.scope_stack = [module_scope]
860
-
861
- def visit_ClassDef(self, node):
862
- bases = get_bases(node)
863
- decs = get_decorators(node)
864
- sig = "class " + node.name
865
- if bases:
866
- sig += "(" + ", ".join(bases) + ")"
867
- sig += ": ..."
868
- syms.append(Sym(
869
- name=node.name,
870
- kind="class",
871
- line=node.lineno,
872
- col=node.col_offset,
873
- signature=sig,
874
- scope=".".join(self.scope_stack) + "." + node.name,
875
- ))
876
- self.scope_stack.append(node.name)
877
- self.generic_visit(node)
878
- self.scope_stack.pop()
879
-
880
- def visit_FunctionDef(self, node):
881
- decs = get_decorators(node)
882
- args = get_args(node.args)
883
- returns = get_returns(node)
884
- is_async = isinstance(node, ast.AsyncFunctionDef)
885
-
886
- kind = "function"
887
- prefix = "def "
888
- if decs:
889
- for d in decs:
890
- if d.endswith(".staticmethod"):
891
- kind = "staticmethod"
892
- elif d.endswith(".classmethod"):
893
- kind = "classmethod"
894
- elif d == "property":
895
- kind = "property"
896
-
897
- if is_async:
898
- kind = "async_" + kind
899
-
900
- sig = f"{prefix}{node.name}({args})"
901
- if returns:
902
- sig += f" -> {returns}"
903
- scope = ".".join(self.scope_stack) + "." + node.name
904
-
905
- syms.append(Sym(
906
- name=node.name,
907
- kind=kind,
908
- line=node.lineno,
909
- col=node.col_offset,
910
- signature=sig,
911
- scope=scope,
912
- ))
913
- # Don't descend into function bodies to avoid local symbols
914
- # self.generic_visit(node)
915
-
916
- def visit_AsyncFunctionDef(self, node):
917
- # Treat as function
918
- self.visit_FunctionDef(node)
919
-
920
- def visit_Assign(self, node):
921
- for target in node.targets:
922
- if isinstance(target, ast.Name):
923
- name = target.id
924
- if is_private(name):
925
- continue
926
- # Infer constness from UPPER_CASE naming
927
- kind = "const" if name.isupper() else "var"
928
- col = target.col_offset if hasattr(target, 'col_offset') else 0
929
- syms.append(Sym(
930
- name=name,
931
- kind=kind,
932
- line=node.lineno,
933
- col=col,
934
- signature=f"{name} = ...",
935
- scope=".".join(self.scope_stack),
936
- ))
937
-
938
- def visit_AnnAssign(self, node):
939
- if isinstance(node.target, ast.Name):
940
- name = node.target.id
941
- if is_private(name):
942
- return
943
- kind = "const" if name.isupper() else "var"
944
- col = node.target.col_offset if hasattr(node.target, 'col_offset') else 0
945
- sig = f"{name}: {get_name(node.annotation)}"
946
- if node.value:
947
- sig += " = ..."
948
- syms.append(Sym(
949
- name=name,
950
- kind=kind,
951
- line=node.lineno,
952
- col=col,
953
- signature=sig,
954
- scope=".".join(self.scope_stack),
955
- ))
956
-
957
- def visit_Import(self, node):
958
- for alias in node.names:
959
- name = alias.asname or alias.name
960
- syms.append(Sym(
961
- name=name,
962
- kind="import",
963
- line=node.lineno,
964
- col=node.col_offset,
965
- signature=f"import {alias.name}",
966
- scope=".".join(self.scope_stack),
967
- ))
968
-
969
- def visit_ImportFrom(self, node):
970
- module = node.module or ""
971
- for alias in node.names:
972
- name = alias.asname or alias.name
973
- syms.append(Sym(
974
- name=name,
975
- kind="import",
976
- line=node.lineno,
977
- col=node.col_offset,
978
- signature=f"from {module} import {alias.name}",
979
- scope=".".join(self.scope_stack),
980
- ))
981
-
982
- visitor = ModuleVisitor()
983
- visitor.visit(tree)
984
-
985
- # Refs need a separate full walk: ModuleVisitor deliberately does not descend
986
- # into function bodies (it would index locals as symbols), but that is exactly
987
- # where the calls are.
988
- for node in ast.walk(tree):
989
- if isinstance(node, ast.Call):
990
- name = leaf_name(node.func)
991
- if name:
992
- refs.append({"toName": name, "callType": "call", "line": node.lineno})
993
- elif isinstance(node, ast.Import):
994
- for alias in node.names:
995
- refs.append({
996
- "toName": alias.name.split(".")[-1],
997
- "callType": "import",
998
- "line": node.lineno,
999
- "module": alias.name,
1000
- })
1001
- elif isinstance(node, ast.ImportFrom):
1002
- # PEP 328: node.level is the number of leading dots. Preserving them is
1003
- # what lets the resolver walk up from the importing file's package \u2014
1004
- # dropping them made \`from .foo import X\` indistinguishable from an
1005
- # absolute \`foo\`.
1006
- module = ("." * (node.level or 0)) + (node.module or "")
1007
- for alias in node.names:
1008
- refs.append({
1009
- "toName": alias.name,
1010
- "callType": "import",
1011
- "line": node.lineno,
1012
- "module": module,
1013
- })
1014
- elif isinstance(node, ast.ClassDef):
1015
- for base in node.bases:
1016
- name = leaf_name(base)
1017
- if name:
1018
- refs.append({"toName": name, "callType": "inherit", "line": node.lineno})
1019
-
1020
- print(json.dumps({"symbols": [s.to_dict() for s in syms], "refs": refs}))
1021
- `;
1022
- _cachedScriptPath = null;
1023
- }
1024
- });
1025
-
1026
- // src/codebase-index/ts-parser.ts
1027
- var ts_parser_exports = {};
1028
- __export(ts_parser_exports, {
1029
- detectLang: () => detectLang,
1030
- parseSymbols: () => parseSymbols3
1031
- });
1032
- function loadTypescript() {
1033
- tsLoad ??= import("@typescript/typescript6").then((m) => {
1034
- ts = m.default ?? m;
1035
- return ts;
1036
- });
1037
- return tsLoad;
1038
- }
1039
- function kindMap() {
1040
- kindMapCache ??= {
1041
- [ts.SyntaxKind.ClassDeclaration]: "class",
1042
- [ts.SyntaxKind.InterfaceDeclaration]: "interface",
1043
- [ts.SyntaxKind.EnumDeclaration]: "enum",
1044
- [ts.SyntaxKind.TypeAliasDeclaration]: "type",
1045
- [ts.SyntaxKind.FunctionDeclaration]: "function",
1046
- [ts.SyntaxKind.MethodDeclaration]: "method",
1047
- [ts.SyntaxKind.GetAccessor]: "property",
1048
- [ts.SyntaxKind.SetAccessor]: "property",
1049
- [ts.SyntaxKind.PropertyDeclaration]: "property",
1050
- [ts.SyntaxKind.Parameter]: "parameter",
1051
- [ts.SyntaxKind.NamespaceExportDeclaration]: "namespace"
1052
- };
1053
- return kindMapCache;
1054
- }
1055
- function kindOf(node) {
1056
- if (ts.isVariableDeclaration(node)) {
1057
- const parent = node.parent;
1058
- if (ts.isVariableDeclarationList(parent)) {
1059
- const flags = parent.flags;
1060
- if (flags & ts.NodeFlags.Let) return "let";
1061
- if (flags & ts.NodeFlags.Const) return "const";
1062
- return "var";
1063
- }
1064
- }
1065
- if (ts.isModuleDeclaration(node)) return "namespace";
1066
- return kindMap()[node.kind] ?? null;
1067
- }
1068
- function getSignature(printer, node, sourceFile) {
1069
- const raw = printer.printNode(ts.EmitHint.Unspecified, node, sourceFile);
1070
- return raw.replace(/\s+/g, " ").slice(0, 500);
1071
- }
1072
- function getJsDoc(node, sourceFile) {
1073
- const fullText = sourceFile.getFullText();
1074
- const nodePos = node.getFullStart();
1075
- const comments = ts.getLeadingCommentRanges(fullText, nodePos);
1076
- if (!comments) return "";
1077
- for (const range of comments) {
1078
- const commentText = fullText.slice(range.pos, range.end);
1079
- const trimmed = commentText.trim();
1080
- if (trimmed.startsWith("/**") && trimmed.endsWith("*/")) {
1081
- const inner = trimmed.slice(3, -2).replace(/^[ \t]*\*[ ]?/gm, "").trim();
1082
- return inner.split("\n")[0]?.trim().slice(0, 200) ?? "";
1083
- }
1084
- }
1085
- return "";
1086
- }
1087
- function pushScopeName(node, parts) {
1088
- if (ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isEnumDeclaration(node) || ts.isTypeAliasDeclaration(node)) {
1089
- parts.push(node.name?.text ?? "Anon");
1090
- } else if (ts.isMethodDeclaration(node) || ts.isGetAccessor(node) || ts.isSetAccessor(node) || ts.isPropertyDeclaration(node) || ts.isFunctionDeclaration(node)) {
1091
- if (node.name && ts.isIdentifier(node.name)) {
1092
- parts.push(node.name.text);
1093
- }
1094
- }
1095
- }
1096
- async function parseSymbols3(opts) {
1097
- const { file, content, lang } = opts;
1098
- await loadTypescript();
1099
- let sourceFile;
1100
- try {
1101
- sourceFile = ts.createSourceFile(file, content, ts.ScriptTarget.Latest, true);
1102
- } catch {
1103
- return { file, lang, symbols: [], mtimeMs: Date.now() };
1104
- }
1105
- const symbols = [];
1106
- const refs = [];
1107
- const printer = ts.createPrinter({});
1108
- function visit(node, funcDepth, scopeParts) {
1109
- const kind = kindOf(node);
1110
- if (kind) {
1111
- if ((kind === "const" || kind === "let" || kind === "var" || kind === "parameter") && funcDepth > 0) {
1112
- } else {
1113
- const nameNode = node.name;
1114
- if (!nameNode || !ts.isIdentifier(nameNode)) {
1115
- return;
1116
- }
1117
- const name = nameNode.text;
1118
- const pos2 = nameNode.getStart(sourceFile);
1119
- const { line: line2, character } = sourceFile.getLineAndCharacterOfPosition(pos2);
1120
- const scope = scopeParts.join(".");
1121
- const signature = getSignature(printer, node, sourceFile);
1122
- const docComment = getJsDoc(node, sourceFile);
1123
- const text = [name, signature, docComment].filter(Boolean).join(" | ");
1124
- symbols.push({
1125
- id: 0,
1126
- lang,
1127
- kind,
1128
- name,
1129
- file,
1130
- line: line2 + 1,
1131
- col: character,
1132
- signature,
1133
- docComment,
1134
- scope,
1135
- text
1136
- });
1137
- }
1138
- }
1139
- const pos = node.getStart(sourceFile);
1140
- const { line } = sourceFile.getLineAndCharacterOfPosition(pos);
1141
- const lineNum = line + 1;
1142
- if (ts.isCallExpression(node)) {
1143
- const expr = node.expression;
1144
- if (ts.isIdentifier(expr)) {
1145
- refs.push({ fromId: 0, toName: expr.text, callType: "call", line: lineNum });
1146
- }
1147
- } else if (ts.isPropertyAccessExpression(node)) {
1148
- if (ts.isIdentifier(node.expression)) {
1149
- refs.push({ fromId: 0, toName: node.expression.text, callType: "call", line: lineNum });
1150
- }
1151
- } else if (ts.isTypeReferenceNode(node)) {
1152
- const name = getTypeName(node.typeName);
1153
- if (name) refs.push({ fromId: 0, toName: name, callType: "type_ref", line: lineNum });
1154
- } else if (ts.isHeritageClause(node)) {
1155
- for (const t of node.types) {
1156
- const name = getTypeName(t.expression);
1157
- if (name)
1158
- refs.push({
1159
- fromId: 0,
1160
- toName: name,
1161
- callType: node.token === ts.SyntaxKind.ExtendsKeyword ? "inherit" : "implement",
1162
- line: lineNum
1163
- });
1164
- }
1165
- } else if (ts.isImportDeclaration(node)) {
1166
- emitImportSpecifierRefs(node, refs, lineNum);
1167
- } else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
1168
- emitExportSpecifierRefs(node, refs, lineNum);
1169
- }
1170
- const scopeIdx = scopeParts.length;
1171
- pushScopeName(node, scopeParts);
1172
- const childFuncDepth = ts.isFunctionLike(node) ? funcDepth + 1 : funcDepth;
1173
- ts.forEachChild(node, (child) => visit(child, childFuncDepth, scopeParts));
1174
- scopeParts.length = scopeIdx;
1175
- }
1176
- visit(sourceFile, 0, []);
1177
- return { file, lang, symbols, refs: deduplicateRefs(refs), mtimeMs: Date.now() };
1178
- }
1179
- function getTypeName(name) {
1180
- if (ts.isIdentifier(name)) return name.text;
1181
- if (ts.isQualifiedName(name)) return `${getTypeName(name.left)}.${name.right.text}`;
1182
- return "";
1183
- }
1184
- function deduplicateRefs(refs) {
1185
- const seen = /* @__PURE__ */ new Set();
1186
- return refs.filter((r) => {
1187
- const key = `${r.toName}:${r.callType}:${r.line}:${r.module ?? ""}`;
1188
- if (seen.has(key)) return false;
1189
- seen.add(key);
1190
- return true;
1191
- });
1192
- }
1193
- function getImportSpecifierName(spec) {
1194
- return spec.propertyName?.text ?? spec.name.text;
1195
- }
1196
- function emitImportSpecifierRefs(node, refs, lineNum) {
1197
- const module = moduleSpecifierOf(node.moduleSpecifier);
1198
- const clause = node.importClause;
1199
- if (!clause) {
1200
- if (module) {
1201
- refs.push({ fromId: 0, toName: module, callType: "import", line: lineNum, module });
1202
- }
1203
- return;
1204
- }
1205
- if (clause.name) {
1206
- refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum, module });
1207
- }
1208
- const bindings = clause.namedBindings;
1209
- if (!bindings) return;
1210
- if (ts.isNamedImports(bindings)) {
1211
- for (const element of bindings.elements) {
1212
- refs.push({
1213
- fromId: 0,
1214
- toName: getImportSpecifierName(element),
1215
- callType: "import",
1216
- line: lineNum,
1217
- module
1218
- });
1219
- }
1220
- } else if (ts.isNamespaceImport(bindings)) {
1221
- refs.push({
1222
- fromId: 0,
1223
- toName: bindings.name.text,
1224
- callType: "import",
1225
- line: lineNum,
1226
- module
1227
- });
1228
- }
1229
- }
1230
- function moduleSpecifierOf(node) {
1231
- return node && ts.isStringLiteral(node) ? node.text : void 0;
1232
- }
1233
- function emitExportSpecifierRefs(node, refs, lineNum) {
1234
- const module = moduleSpecifierOf(node.moduleSpecifier);
1235
- const clause = node.exportClause;
1236
- if (clause && ts.isNamespaceExport(clause)) {
1237
- refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum, module });
1238
- return;
1239
- }
1240
- if (clause && ts.isNamedExports(clause)) {
1241
- for (const element of clause.elements) {
1242
- const originalName = element.propertyName?.text ?? element.name.text;
1243
- refs.push({ fromId: 0, toName: originalName, callType: "import", line: lineNum, module });
1244
- }
1245
- return;
1246
- }
1247
- if (module) {
1248
- refs.push({ fromId: 0, toName: module, callType: "import", line: lineNum, module });
1249
- }
1250
- }
1251
- var ts, tsLoad, kindMapCache;
1252
- var init_ts_parser = __esm({
1253
- "src/codebase-index/ts-parser.ts"() {
1254
- "use strict";
1255
- init_languages();
1256
- tsLoad = null;
1257
- kindMapCache = null;
1258
- }
1259
- });
1260
-
1261
- // src/codebase-index/go-parser.ts
1262
- var go_parser_exports = {};
1263
- __export(go_parser_exports, {
1264
- detectLang: () => detectLang,
1265
- parseSymbols: () => parseSymbols4
1266
- });
1267
- import { spawn as spawn3 } from "node:child_process";
1268
- import * as os3 from "node:os";
1269
- import * as path5 from "node:path";
1270
- import * as fs4 from "node:fs/promises";
1271
- async function parseSymbols4(opts) {
1272
- const { file, content, lang } = opts;
1273
- try {
1274
- const parsed = await withSpawnGate(() => syncGoParse(file, content, lang));
1275
- if (parsed.symbols.length > 0) {
1276
- return parsed;
1277
- }
1278
- const fallback = fallbackParse(file, content, lang);
1279
- return parsed.refs?.length ? { ...fallback, refs: parsed.refs } : fallback;
1280
- } catch {
1281
- return fallbackParse(file, content, lang);
1282
- }
1283
- }
1284
- function fallbackParse(filePath, content, lang) {
1285
- if (!/^\s*package\s+[A-Za-z_]\w*/m.test(content) || hasUnbalancedDelimiters(content)) {
1286
- return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
1287
- }
1288
- const symbols = [];
1289
- const packageName = content.match(/^\s*package\s+([A-Za-z_]\w*)/m)?.[1] ?? "";
1290
- const lines = content.split(/\r?\n/);
1291
- for (const [idx, line] of lines.entries()) {
1292
- const trimmed = line.trimStart();
1293
- const col = line.length - trimmed.length + 1;
1294
- const fn = /^func\s+(?:\([^)]*\)\s*)?([A-Za-z_]\w*)\s*\(/.exec(trimmed);
1295
- if (fn?.[1]) {
1296
- addFallbackSymbol(symbols, {
1297
- filePath,
1298
- lang,
1299
- kind: trimmed.startsWith("func (") ? "method" : "function",
1300
- name: fn[1],
1301
- line: idx + 1,
1302
- col,
1303
- signature: trimmed,
1304
- scope: packageName ? `${packageName}.${fn[1]}` : fn[1]
1305
- });
1306
- continue;
1307
- }
1308
- const typeDecl = /^type\s+([A-Za-z_]\w*)\b/.exec(trimmed);
1309
- if (typeDecl?.[1]) {
1310
- addFallbackSymbol(symbols, {
1311
- filePath,
1312
- lang,
1313
- kind: "type",
1314
- name: typeDecl[1],
1315
- line: idx + 1,
1316
- col,
1317
- signature: trimmed,
1318
- scope: packageName
1319
- });
1320
- continue;
1321
- }
1322
- const valueDecl = /^(const|var)\s+([A-Za-z_]\w*)\b/.exec(trimmed);
1323
- if (valueDecl?.[1] && valueDecl[2]) {
1324
- addFallbackSymbol(symbols, {
1325
- filePath,
1326
- lang,
1327
- kind: valueDecl[1],
1328
- name: valueDecl[2],
1329
- line: idx + 1,
1330
- col,
1331
- signature: trimmed,
1332
- scope: packageName
1333
- });
1334
- }
1335
- }
1336
- return { file: filePath, lang, symbols, mtimeMs: Date.now() };
1337
- }
1338
- function addFallbackSymbol(symbols, opts) {
1339
- symbols.push({
1340
- id: 0,
1341
- lang: opts.lang,
1342
- kind: opts.kind,
1343
- name: opts.name,
1344
- file: opts.filePath,
1345
- line: opts.line,
1346
- col: opts.col,
1347
- signature: opts.signature,
1348
- docComment: "",
1349
- scope: opts.scope,
1350
- text: `${opts.name} ${opts.signature}`.trim()
1351
- });
1352
- }
1353
- function hasUnbalancedDelimiters(content) {
1354
- const pairs = { "(": ")", "[": "]", "{": "}" };
1355
- const closers = new Set(Object.values(pairs));
1356
- const stack = [];
1357
- for (const ch of content) {
1358
- if (pairs[ch]) {
1359
- stack.push(pairs[ch]);
1360
- } else if (closers.has(ch) && stack.pop() !== ch) {
1361
- return true;
1362
- }
1363
- }
1364
- return stack.length > 0;
1365
- }
1366
- async function syncGoParse(filePath, content, lang) {
1367
- try {
1368
- let scriptPath = _cachedGoScriptPath;
1369
- if (!scriptPath) {
1370
- const tmpDir = await fs4.mkdtemp(path5.join(os3.tmpdir(), "ws-go-parse-"));
1371
- scriptPath = path5.join(tmpDir, "parse.go");
1372
- await fs4.writeFile(scriptPath, GO_PARSE_SCRIPT, "utf8");
1373
- _cachedGoScriptPath = scriptPath;
1374
- }
1375
- const goBinary = resolveWin32Command("go");
1376
- const goResult = await new Promise(
1377
- (resolve, reject) => {
1378
- let settled = false;
1379
- const proc = spawn3(goBinary, ["run", scriptPath], {
1380
- stdio: ["pipe", "pipe", "pipe"],
1381
- windowsHide: true
1382
- });
1383
- proc.on("error", (err) => {
1384
- if (settled) return;
1385
- settled = true;
1386
- reject(err);
1387
- });
1388
- let stdout2 = "";
1389
- proc.stdout?.on("data", (chunk) => {
1390
- stdout2 += chunk.toString();
1391
- });
1392
- proc.stderr?.resume();
1393
- proc.stdin?.write(content);
1394
- proc.stdin?.end();
1395
- const timer = setTimeout(() => {
1396
- if (settled) return;
1397
- settled = true;
1398
- proc.kill("SIGKILL");
1399
- reject(new Error("timeout"));
1400
- }, 15e3);
1401
- timer.unref?.();
1402
- proc.on("close", (code2) => {
1403
- if (settled) return;
1404
- settled = true;
1405
- clearTimeout(timer);
1406
- resolve({ code: code2, stdout: stdout2 });
1407
- });
1408
- }
1409
- );
1410
- const { code, stdout } = goResult;
1411
- if (code !== 0 || !stdout.trim()) {
1412
- return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
1413
- }
1414
- const { symbols: rawSymbols, refs } = parseParserOutput(stdout, lang);
1415
- const symbols = rawSymbols.map((s) => ({
1416
- id: 0,
1417
- lang,
1418
- kind: s.kind,
1419
- name: s.name,
1420
- file: filePath,
1421
- line: s.line,
1422
- col: s.col,
1423
- signature: s.signature ?? "",
1424
- docComment: "",
1425
- scope: s.scope ?? "",
1426
- text: `${s.name} ${s.signature ?? ""}`.trim()
1427
- }));
1428
- return { file: filePath, lang, symbols, refs, mtimeMs: Date.now() };
1429
- } catch {
1430
- return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
1431
- }
1432
- }
1433
- var GO_PARSE_SCRIPT, _cachedGoScriptPath;
1434
- var init_go_parser = __esm({
1435
- "src/codebase-index/go-parser.ts"() {
1436
- "use strict";
1437
- init_win32_resolve();
1438
- init_parser_output();
1439
- init_spawn_gate();
1440
- init_languages();
1441
- GO_PARSE_SCRIPT = `
1442
- package main
1443
-
1444
- import (
1445
- "encoding/json"
1446
- "fmt"
1447
- "go/ast"
1448
- "go/parser"
1449
- "go/token"
1450
- "io"
1451
- "os"
1452
- "strconv"
1453
- "strings"
1454
- )
1455
-
1456
- type Sym struct {
1457
- Name string \`json:"name"\`
1458
- Kind string \`json:"kind"\`
1459
- Line int \`json:"line"\`
1460
- Col int \`json:"col"\`
1461
- Signature string \`json:"signature"\`
1462
- Scope string \`json:"scope"\`
1463
- }
1464
-
1465
- // Ref is a cross-reference emitted alongside the symbols, so one \`go run\`
1466
- // yields both. Module is the import path for CallType "import", else empty.
1467
- type Ref struct {
1468
- ToName string \`json:"toName"\`
1469
- CallType string \`json:"callType"\`
1470
- Line int \`json:"line"\`
1471
- Module string \`json:"module"\`
1472
- }
1473
-
1474
- type Result struct {
1475
- Symbols []Sym \`json:"symbols"\`
1476
- Refs []Ref \`json:"refs"\`
1477
- }
1478
-
1479
- func emptyResult() string {
1480
- return "{\\"symbols\\":[],\\"refs\\":[]}"
1481
- }
1482
-
1483
- func main() {
1484
- src, err := io.ReadAll(os.Stdin)
1485
- if err != nil {
1486
- fmt.Print(emptyResult())
1487
- return
1488
- }
1489
- fset := token.NewFileSet()
1490
- node, err := parser.ParseFile(fset, "src.go", src, 0)
1491
- if err != nil {
1492
- fmt.Print(emptyResult())
1493
- return
1494
- }
1495
-
1496
- var syms []Sym
1497
-
1498
- // Package-level scope
1499
- pkgScope := node.Name.Name
1500
-
1501
- // Collect all top-level declarations
1502
- for _, decl := range node.Decls {
1503
- switch d := decl.(type) {
1504
- case *ast.FuncDecl:
1505
- name := d.Name.Name
1506
- kind := "function"
1507
- scope := pkgScope
1508
- if d.Recv != nil && len(d.Recv.List) > 0 {
1509
- scope = pkgScope + "." + recvTypeName(d.Recv.List[0].Type) + "." + name
1510
- kind = "method"
1511
- } else {
1512
- scope = pkgScope + "." + name
1513
- }
1514
- pos := fset.Position(d.Pos())
1515
- sig := formatFuncSig(d)
1516
- syms = append(syms, Sym{Name: name, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: scope})
1517
-
1518
- case *ast.GenDecl:
1519
- for _, spec := range d.Specs {
1520
- switch s := spec.(type) {
1521
- case *ast.TypeSpec:
1522
- name := s.Name.Name
1523
- pos := fset.Position(s.Pos())
1524
- sig := "type " + name
1525
- if s.TypeParams != nil {
1526
- sig += formatTypeParams(s.TypeParams)
1527
- }
1528
- if st, ok := s.Type.(*ast.StructType); ok {
1529
- sig += " = struct { " + formatFields(st.Fields.List) + " }"
1530
- } else if it, ok := s.Type.(*ast.InterfaceType); ok {
1531
- sig += " = interface { " + formatMethods(it.Methods.List) + " }"
1532
- } else {
1533
- sig += " = " + formatType(s.Type)
1534
- }
1535
- syms = append(syms, Sym{Name: name, Kind: "type", Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
1536
-
1537
- case *ast.ValueSpec:
1538
- for _, n := range s.Names {
1539
- name := n.Name
1540
- pos := fset.Position(n.Pos())
1541
- kind := "var"
1542
- if d.Tok == token.CONST {
1543
- kind = "const"
1544
- }
1545
- sig := kind + " " + name
1546
- if s.Type != nil {
1547
- sig += " " + formatType(s.Type)
1548
- }
1549
- syms = append(syms, Sym{Name: name, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
1550
- }
1551
- }
1552
- }
1553
- }
1554
- }
1555
-
1556
- refs := []Ref{}
1557
- ast.Inspect(node, func(n ast.Node) bool {
1558
- switch expr := n.(type) {
1559
- case *ast.CallExpr:
1560
- line := fset.Position(expr.Pos()).Line
1561
- switch fun := expr.Fun.(type) {
1562
- case *ast.Ident:
1563
- refs = append(refs, Ref{ToName: fun.Name, CallType: "call", Line: line})
1564
- case *ast.SelectorExpr:
1565
- // Record the selected name (\`Join\` of \`filepath.Join\`): it is the
1566
- // declared symbol name, so it resolves the same way the TypeScript
1567
- // and Python extractors' call refs do.
1568
- refs = append(refs, Ref{ToName: fun.Sel.Name, CallType: "call", Line: line})
1569
- }
1570
- case *ast.ImportSpec:
1571
- if expr.Path != nil {
1572
- if importPath, uerr := strconv.Unquote(expr.Path.Value); uerr == nil {
1573
- line := fset.Position(expr.Pos()).Line
1574
- // A Go import names a package, not a symbol; the package's
1575
- // last path segment is the name it is referenced by.
1576
- name := importPath
1577
- if idx := strings.LastIndex(importPath, "/"); idx >= 0 {
1578
- name = importPath[idx+1:]
1579
- }
1580
- refs = append(refs, Ref{ToName: name, CallType: "import", Line: line, Module: importPath})
1581
- }
1582
- }
1583
- }
1584
- return true
1585
- })
1586
-
1587
- if syms == nil {
1588
- syms = []Sym{}
1589
- }
1590
- data, err := json.Marshal(Result{Symbols: syms, Refs: refs})
1591
- if err != nil {
1592
- fmt.Print(emptyResult())
1593
- return
1594
- }
1595
- fmt.Print(string(data))
1596
- }
1597
-
1598
- func recvTypeName(t ast.Expr) string {
1599
- switch v := t.(type) {
1600
- case *ast.Ident:
1601
- return v.Name
1602
- case *ast.StarExpr:
1603
- return recvTypeName(v.X)
1604
- default:
1605
- return "?"
1606
- }
1607
- }
1608
-
1609
- func formatFuncSig(d *ast.FuncDecl) string {
1610
- scope := ""
1611
- if d.Recv != nil && len(d.Recv.List) > 0 {
1612
- scope = "(" + formatFieldList(d.Recv.List) + ") "
1613
- }
1614
- scope += formatFuncType(d.Type)
1615
- return "func " + scope
1616
- }
1617
-
1618
- func formatFuncType(f *ast.FuncType) string {
1619
- params := formatFieldList(f.Params.List)
1620
- results := ""
1621
- if f.Results != nil {
1622
- results = " -> " + formatFieldList(f.Results.List)
1623
- }
1624
- return params + results
1625
- }
1626
-
1627
- func formatFieldList(fields []*ast.Field) string {
1628
- if len(fields) == 0 {
1629
- return "()"
1630
- }
1631
- names := make([]string, 0, len(fields))
1632
- for _, f := range fields {
1633
- name := ""
1634
- if len(f.Names) > 0 {
1635
- name = f.Names[0].Name
1636
- }
1637
- t := formatType(f.Type)
1638
- if name != "" {
1639
- names = append(names, name+" "+t)
1640
- } else {
1641
- names = append(names, t)
1642
- }
1643
- }
1644
- return "(" + strings.Join(names, ", ") + ")"
1645
- }
1646
-
1647
- func formatFields(fields []*ast.Field) string {
1648
- lines := make([]string, 0)
1649
- for _, f := range fields {
1650
- name := ""
1651
- if len(f.Names) > 0 {
1652
- name = f.Names[0].Name
1653
- }
1654
- t := formatType(f.Type)
1655
- if name != "" {
1656
- lines = append(lines, name+" "+t)
1657
- } else {
1658
- lines = append(lines, t)
1659
- }
1660
- }
1661
- return strings.Join(lines, "; ")
1662
- }
1663
-
1664
- func formatMethods(fields []*ast.Field) string {
1665
- return formatFields(fields)
1666
- }
1667
-
1668
- func formatTypeParams(tp *ast.FieldList) string {
1669
- if tp == nil || len(tp.List) == 0 {
1670
- return ""
1671
- }
1672
- params := make([]string, len(tp.List))
1673
- for i, p := range tp.List {
1674
- if len(p.Names) > 0 {
1675
- params[i] = p.Names[0].Name
1676
- } else {
1677
- params[i] = "T"
1678
- }
1679
- }
1680
- return "[" + strings.Join(params, ", ") + "]"
1681
- }
1682
-
1683
- func formatType(t ast.Expr) string {
1684
- if t == nil {
1685
- return "?"
1686
- }
1687
- switch v := t.(type) {
1688
- case *ast.Ident:
1689
- return v.Name
1690
- case *ast.SelectorExpr:
1691
- return formatType(v.X) + "." + v.Sel.Name
1692
- case *ast.StarExpr:
1693
- return "*" + formatType(v.X)
1694
- case *ast.ArrayType:
1695
- if v.Len == nil {
1696
- return "[]" + formatType(v.Elt)
1697
- }
1698
- return "[...]" + formatType(v.Elt)
1699
- case *ast.MapType:
1700
- return "map[" + formatType(v.Key) + "]" + formatType(v.Value)
1701
- case *ast.InterfaceType:
1702
- return "interface{}"
1703
- case *ast.StructType:
1704
- return "struct{}"
1705
- case *ast.FuncType:
1706
- return formatFuncType(v)
1707
- case *ast.ChanType:
1708
- return "chan " + formatType(v.Value)
1709
- case *ast.BasicLit:
1710
- return v.Value
1711
- case *ast.IndexExpr:
1712
- // Generic instantiation with one type arg, e.g. Logger[int].
1713
- return formatType(v.X) + "[" + formatType(v.Index) + "]"
1714
- case *ast.IndexListExpr:
1715
- // Generic instantiation with multiple type args, e.g. Map[K, V].
1716
- args := make([]string, len(v.Indices))
1717
- for i, idx := range v.Indices {
1718
- args[i] = formatType(idx)
1719
- }
1720
- return formatType(v.X) + "[" + strings.Join(args, ", ") + "]"
1721
- default:
1722
- return "?"
1723
- }
1724
- }
1725
- `;
1726
- _cachedGoScriptPath = null;
1727
- }
1728
- });
1729
-
1730
- // src/codebase-index/rs-parser.ts
1731
- var rs_parser_exports = {};
1732
- __export(rs_parser_exports, {
1733
- detectLang: () => detectLang,
1734
- parseSymbols: () => parseSymbols5
1735
- });
1736
- import { expectDefined } from "@wrongstack/core/utils";
1737
- async function parseSymbols5(opts) {
1738
- const { file, content, lang } = opts;
1739
- return regexParse({ file, content, lang });
1740
- }
1741
- function regexParse(opts) {
1742
- const { file, content, lang } = opts;
1743
- const symbols = [];
1744
- const lines = content.split("\n");
1745
- const lineOffsets = [0];
1746
- for (let i = 0; i < lines.length; i++) {
1747
- lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
1748
- }
1749
- function lineFromOffset(offset) {
1750
- let lo = 0;
1751
- let hi = lineOffsets.length - 1;
1752
- while (lo < hi) {
1753
- const mid = lo + hi + 1 >>> 1;
1754
- if (expectDefined(lineOffsets[mid]) <= offset) lo = mid;
1755
- else hi = mid - 1;
1756
- }
1757
- return lo + 1;
1758
- }
1759
- function extractDeclaration(lineIdx, _match) {
1760
- const line = lines[lineIdx] ?? "";
1761
- return line.trim().slice(0, 500);
1762
- }
1763
- for (const pattern of RS_PATTERNS) {
1764
- pattern.regex.lastIndex = 0;
1765
- for (let match = pattern.regex.exec(content); match !== null; match = pattern.regex.exec(content)) {
1766
- const name = expectDefined(match[1]);
1767
- const offset = match.index ?? 0;
1768
- const line = lineFromOffset(offset);
1769
- const col = offset - (lineOffsets[line - 1] ?? 0);
1770
- const lineIdx = line - 1;
1771
- const signature = extractDeclaration(lineIdx, match);
1772
- symbols.push({
1773
- id: 0,
1774
- lang,
1775
- kind: pattern.kind,
1776
- name,
1777
- file,
1778
- line,
1779
- col,
1780
- signature,
1781
- docComment: "",
1782
- scope: "",
1783
- text: `${name} ${signature}`.trim()
1784
- });
1785
- }
1786
- }
1787
- const seen = /* @__PURE__ */ new Set();
1788
- const deduped = symbols.filter((s) => {
1789
- const key = `${s.name}:${s.line}`;
1790
- if (seen.has(key)) return false;
1791
- seen.add(key);
1792
- return true;
1793
- });
1794
- return { file, lang, symbols: deduped, mtimeMs: Date.now() };
1795
- }
1796
- var RS_PATTERNS;
1797
- var init_rs_parser = __esm({
1798
- "src/codebase-index/rs-parser.ts"() {
1799
- "use strict";
1800
- init_languages();
1801
- RS_PATTERNS = [
1802
- { regex: /fn\s+(\w+)\s*\([^)]*\)/g, kind: "function" },
1803
- { regex: /struct\s+(\w+)/g, kind: "struct" },
1804
- { regex: /enum\s+(\w+)/g, kind: "enum" },
1805
- { regex: /trait\s+(\w+)/g, kind: "trait" },
1806
- { regex: /impl\s+(?:<[^>]+>)?(\w+)/g, kind: "impl" },
1807
- { regex: /type\s+(\w+)\s*=/g, kind: "type" },
1808
- { regex: /const\s+(\w+)/g, kind: "const" },
1809
- { regex: /static\s+(\w+)/g, kind: "static" },
1810
- { regex: /mod\s+(\w+)/g, kind: "mod" }
1811
- ];
1812
- }
1813
- });
1814
-
1815
- // src/codebase-index/json-parser.ts
1816
- var json_parser_exports = {};
1817
- __export(json_parser_exports, {
1818
- detectLang: () => detectLang,
1819
- parseSymbols: () => parseSymbols6
1820
- });
1821
- import { expectDefined as expectDefined2 } from "@wrongstack/core/utils";
1822
- import * as path6 from "node:path";
1823
- function parseSymbols6(opts) {
1824
- const { file, content, lang } = opts;
1825
- try {
1826
- return regexParse2({ file, content, lang });
1827
- } catch {
1828
- return { file, lang, symbols: [], mtimeMs: Date.now() };
1829
- }
1830
- }
1831
- function regexParse2(opts) {
1832
- const { file, content, lang } = opts;
1833
- const symbols = [];
1834
- const basename3 = path6.basename(file).toLowerCase();
1835
- const isPackageJson = basename3 === "package.json";
1836
- const isTsconfig = basename3 === "tsconfig.json" || basename3 === "tsconfig.build.json";
1837
- const isJsonSchema = content.includes("$schema") || content.includes("$id") || content.includes("$ref");
1838
- const isOpenApi = content.includes("openapi") || content.includes("swagger");
1839
- const lines = content.split("\n");
1840
- const lineOffsets = [0];
1841
- for (let i = 0; i < lines.length; i++) {
1842
- lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
1843
- }
1844
- function lineFromOffset(offset) {
1845
- let lo = 0;
1846
- let hi = lineOffsets.length - 1;
1847
- while (lo < hi) {
1848
- const mid = lo + hi + 1 >>> 1;
1849
- if (expectDefined2(lineOffsets[mid]) <= offset) lo = mid;
1850
- else hi = mid - 1;
1851
- }
1852
- return lo + 1;
1853
- }
1854
- const rootMatch = content.match(/^\s*\{/m);
1855
- if (rootMatch) {
1856
- const offset = expectDefined2(rootMatch.index);
1857
- const line = lineFromOffset(offset);
1858
- symbols.push(
1859
- makeSymbol({
1860
- name: path6.basename(file),
1861
- kind: "object",
1862
- line,
1863
- col: 0,
1864
- signature: `"${path6.basename(file)}" = { ... }`,
1865
- file,
1866
- lang
1867
- })
1868
- );
1869
- }
1870
- const topLevelKeyRegex = /^\s*"([^"]+)"\s*:/gm;
1871
- for (let match = topLevelKeyRegex.exec(content); match !== null; match = topLevelKeyRegex.exec(content)) {
1872
- const key = expectDefined2(match[1]);
1873
- const offset = match.index ?? 0;
1874
- const line = lineFromOffset(offset);
1875
- const col = offset - (lineOffsets[line - 1] ?? 0);
1876
- let kind = "property";
1877
- let signature = `"${key}": ..."`;
1878
- if (isPackageJson) {
1879
- if (key === "scripts" || key === "dependencies" || key === "devDependencies" || key === "peerDependencies" || key === "optionalDependencies") {
1880
- kind = "const";
1881
- signature = `"${key}": { ... }`;
1882
- }
1883
- } else if (isTsconfig) {
1884
- if (key === "compilerOptions") {
1885
- kind = "property";
1886
- signature = `"compilerOptions": { ... }`;
1887
- }
1888
- }
1889
- if (isJsonSchema || isOpenApi) {
1890
- if (key === "$schema" || key === "$id") {
1891
- kind = "schema";
1892
- signature = `"${key}": "..."`;
1893
- } else if (key === "$ref") {
1894
- kind = "schema";
1895
- signature = `"$ref": "..."`;
1896
- }
1897
- }
1898
- symbols.push(
1899
- makeSymbol({
1900
- name: key,
1901
- kind,
1902
- line,
1903
- col,
1904
- signature,
1905
- file,
1906
- lang
1907
- })
1908
- );
1909
- if (isPackageJson && key === "scripts") {
1910
- extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset);
1911
- }
1912
- if (isTsconfig && key === "compilerOptions") {
1913
- extractCompilerOptions(content, symbols, file, lang, lineOffsets, line, lineFromOffset);
1914
- }
1915
- }
1916
- const defsRegex = /"\$defs"\s*:|"\$defs"\s*:/g;
1917
- const defsMatch = defsRegex.exec(content);
1918
- if (defsMatch !== null) {
1919
- const offset = expectDefined2(defsMatch.index);
1920
- const line = lineFromOffset(offset);
1921
- symbols.push(
1922
- makeSymbol({
1923
- name: "$defs",
1924
- kind: "property",
1925
- line,
1926
- col: offset - (lineOffsets[line - 1] ?? 0),
1927
- signature: '"$defs": { ... }',
1928
- file,
1929
- lang
1930
- })
1931
- );
1932
- }
1933
- const defsPatterns = [
1934
- /"\$defs"\s*:/g,
1935
- /"definitions"\s*:/g,
1936
- /"components"\s*:/g,
1937
- /"schemas"\s*:/g
1938
- ];
1939
- for (const pat of defsPatterns) {
1940
- pat.lastIndex = 0;
1941
- for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {
1942
- const offset = match.index ?? 0;
1943
- const line = lineFromOffset(offset);
1944
- const key = match[0]?.match(/"([^"]+)"/)?.[1] ?? expectDefined2(match[0]);
1945
- symbols.push(
1946
- makeSymbol({
1947
- name: key,
1948
- kind: "property",
1949
- line,
1950
- col: offset - (lineOffsets[line - 1] ?? 0),
1951
- signature: `"${key}": { ... }`,
1952
- file,
1953
- lang
1954
- })
1955
- );
1956
- }
1957
- }
1958
- return { file, lang, symbols, mtimeMs: Date.now() };
1959
- }
1960
- function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset) {
1961
- const scriptsBlockRegex = /"scripts"\s*:\s*\{([^}]+)\}/g;
1962
- for (let match = scriptsBlockRegex.exec(content); match !== null; match = scriptsBlockRegex.exec(content)) {
1963
- const blockContent = expectDefined2(match[0]);
1964
- const blockOffset = match.index ?? 0;
1965
- const scriptKeyRegex = /"(\w[\w-]*)"\s*:/g;
1966
- for (let scriptMatch = scriptKeyRegex.exec(blockContent); scriptMatch !== null; scriptMatch = scriptKeyRegex.exec(blockContent)) {
1967
- const key = expectDefined2(scriptMatch[1]);
1968
- const keyOffset = blockOffset + expectDefined2(scriptMatch.index);
1969
- const line = lineFromOffset(keyOffset);
1970
- symbols.push(
1971
- makeSymbol({
1972
- name: key,
1973
- kind: "function",
1974
- line,
1975
- col: keyOffset - (lineOffsets[line - 1] ?? 0),
1976
- signature: `"${key}": "..."`,
1977
- file,
1978
- lang
1979
- })
1980
- );
1981
- }
1982
- }
1983
- }
1984
- function extractCompilerOptions(content, symbols, file, lang, lineOffsets, parentLine, lineFromOffset) {
1985
- const optsBlockRegex = /"compilerOptions"\s*:\s*\{([^}]+)\}/g;
1986
- for (let match = optsBlockRegex.exec(content); match !== null; match = optsBlockRegex.exec(content)) {
1987
- const blockContent = expectDefined2(match[0]);
1988
- const blockOffset = match.index ?? 0;
1989
- const optKeyRegex = /"(\w[\w]*)"\s*:/g;
1990
- for (let optMatch = optKeyRegex.exec(blockContent); optMatch !== null; optMatch = optKeyRegex.exec(blockContent)) {
1991
- const key = expectDefined2(optMatch[1]);
1992
- const keyOffset = blockOffset + expectDefined2(optMatch.index);
1993
- const line = lineFromOffset(keyOffset);
1994
- if (line <= parentLine) continue;
1995
- symbols.push(
1996
- makeSymbol({
1997
- name: key,
1998
- kind: "property",
1999
- line,
2000
- col: keyOffset - (lineOffsets[line - 1] ?? 0),
2001
- signature: `"${key}": ...`,
2002
- file,
2003
- lang
2004
- })
2005
- );
2006
- }
2007
- }
2008
- }
2009
- function makeSymbol(opts) {
2010
- return {
2011
- id: 0,
2012
- lang: opts.lang,
2013
- kind: opts.kind,
2014
- name: opts.name,
2015
- file: opts.file,
2016
- line: opts.line,
2017
- col: opts.col,
2018
- signature: opts.signature,
2019
- docComment: "",
2020
- scope: "",
2021
- text: `${opts.name} ${opts.signature}`.trim()
2022
- };
2023
- }
2024
- var init_json_parser = __esm({
2025
- "src/codebase-index/json-parser.ts"() {
2026
- "use strict";
2027
- init_languages();
2028
- }
2029
- });
2030
-
2031
- // src/codebase-index/yaml-parser.ts
2032
- var yaml_parser_exports = {};
2033
- __export(yaml_parser_exports, {
2034
- detectLang: () => detectLang,
2035
- parseSymbols: () => parseSymbols7
2036
- });
2037
- import { expectDefined as expectDefined3, truncate } from "@wrongstack/core/utils";
2038
- function parseSymbols7(opts) {
2039
- const { file, content, lang } = opts;
2040
- try {
2041
- return regexParse3({ file, content, lang });
2042
- } catch {
2043
- return { file, lang, symbols: [], mtimeMs: Date.now() };
2044
- }
2045
- }
2046
- function regexParse3(opts) {
2047
- const { file, content, lang } = opts;
2048
- const symbols = [];
2049
- const lines = content.split("\n");
2050
- const lineOffsets = [0];
2051
- for (let i = 0; i < lines.length; i++) {
2052
- lineOffsets.push((lineOffsets[i] ?? 0) + (lines[i]?.length ?? 0) + 1);
2053
- }
2054
- function lineFromOffset(offset) {
2055
- let lo = 0;
2056
- let hi = lineOffsets.length - 1;
2057
- while (lo < hi) {
2058
- const mid = lo + hi + 1 >>> 1;
2059
- if (expectDefined3(lineOffsets[mid]) <= offset) lo = mid;
2060
- else hi = mid - 1;
2061
- }
2062
- return lo + 1;
2063
- }
2064
- const anchorRegex = /&(\w[\w-]*)/g;
2065
- for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {
2066
- const name = expectDefined3(match[1]);
2067
- const offset = match.index ?? 0;
2068
- const line = lineFromOffset(offset);
2069
- const col = offset - (lineOffsets[line - 1] ?? 0);
2070
- symbols.push(
2071
- makeSymbol2({
2072
- name,
2073
- kind: "const",
2074
- line,
2075
- col,
2076
- signature: `&${name}`,
2077
- file,
2078
- lang
2079
- })
2080
- );
2081
- }
2082
- const aliasRegex = /\*(\w[\w-]*)/g;
2083
- for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {
2084
- const name = expectDefined3(match[1]);
2085
- const offset = match.index ?? 0;
2086
- const line = lineFromOffset(offset);
2087
- const col = offset - (lineOffsets[line - 1] ?? 0);
2088
- symbols.push(
2089
- makeSymbol2({
2090
- name,
2091
- kind: "const",
2092
- line,
2093
- col,
2094
- signature: `*${name}`,
2095
- file,
2096
- lang
2097
- })
2098
- );
2099
- }
2100
- const kvRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:/gm;
2101
- for (let match = kvRegex.exec(content); match !== null; match = kvRegex.exec(content)) {
2102
- const indent = match[1]?.length ?? 0;
2103
- const key = match[2];
2104
- if (!key) continue;
2105
- const offset = match.index ?? 0;
2106
- const line = lineFromOffset(offset);
2107
- const col = offset - (lineOffsets[line - 1] ?? 0);
2108
- const lineContent = lines[line - 1] ?? "";
2109
- if (/^[|&>]/.test(lineContent.trim())) continue;
2110
- if (key === "---" || key === "...") continue;
2111
- if (indent > 12) continue;
2112
- const value = extractValue(content, match.index ?? 0);
2113
- const kind = isScalar(value) ? "literal" : "property";
2114
- const signature = `${key}: ${truncate(value, 60)}`;
2115
- symbols.push(makeSymbol2({ name: key, kind, line, col, signature, file, lang }));
2116
- }
2117
- const listItemRegex = /^-(\s+)([^:#\s][^:#\s]*)\s*:/gm;
2118
- for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {
2119
- const key = expectDefined3(match[2]);
2120
- const offset = match.index ?? 0;
2121
- const line = lineFromOffset(offset);
2122
- const col = offset - (lineOffsets[line - 1] ?? 0);
2123
- const value = extractValue(content, offset + match[0]?.length);
2124
- const kind = isScalar(value) ? "literal" : "property";
2125
- symbols.push(
2126
- makeSymbol2({
2127
- name: key,
2128
- kind,
2129
- line,
2130
- col,
2131
- signature: `- ${key}: ${truncate(value, 60)}`,
2132
- file,
2133
- lang
2134
- })
2135
- );
2136
- }
2137
- const blockScalarRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:\s*[|>](\s|$)/gm;
2138
- for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {
2139
- const key = expectDefined3(match[2]);
2140
- const offset = match.index ?? 0;
2141
- const line = lineFromOffset(offset);
2142
- const col = offset - (lineOffsets[line - 1] ?? 0);
2143
- symbols.push(
2144
- makeSymbol2({
2145
- name: key,
2146
- kind: "property",
2147
- line,
2148
- col,
2149
- signature: `${key}: | ...`,
2150
- file,
2151
- lang
2152
- })
2153
- );
2154
- }
2155
- return { file, lang, symbols, mtimeMs: Date.now() };
2156
- }
2157
- function extractValue(content, afterColonOffset) {
2158
- const lineEnd = content.indexOf("\n", afterColonOffset);
2159
- const rest = content.slice(afterColonOffset, lineEnd < 0 ? void 0 : lineEnd);
2160
- return rest.trim();
2161
- }
2162
- function isScalar(value) {
2163
- if (!value) return false;
2164
- if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?$/.test(value)) return true;
2165
- if (/^(true|false|null|undefined)$/i.test(value)) return true;
2166
- if (/^'[^']*'$/.test(value) || /^"[^"]*"$/.test(value)) return true;
2167
- return false;
2168
- }
2169
- function makeSymbol2(opts) {
2170
- return {
2171
- id: 0,
2172
- lang: opts.lang,
2173
- kind: opts.kind,
2174
- name: opts.name,
2175
- file: opts.file,
2176
- line: opts.line,
2177
- col: opts.col,
2178
- signature: opts.signature,
2179
- docComment: "",
2180
- scope: "",
2181
- text: `${opts.name} ${opts.signature}`.trim()
2182
- };
2183
- }
2184
- var init_yaml_parser = __esm({
2185
- "src/codebase-index/yaml-parser.ts"() {
2186
- "use strict";
2187
- init_languages();
2188
- }
2189
- });
2190
-
2191
- // src/codebase-index/tree-sitter/queries.ts
2192
- function parseGroupedUse(text) {
2193
- const open = text.indexOf("{");
2194
- const close = text.lastIndexOf("}");
2195
- if (open < 0 || close <= open) return null;
2196
- const prefix = text.slice(0, open).replace(/[\\/]+$/, "");
2197
- const out = [];
2198
- for (const rawMember of text.slice(open + 1, close).split(",")) {
2199
- let member = rawMember.trim();
2200
- if (!member) continue;
2201
- member = member.replace(
2202
- /^(static|final|type|class|struct|enum|protocol|var|func|let|typealias|function|const)\s+/i,
2203
- ""
2204
- ).trim();
2205
- if (!member) continue;
2206
- const aliasMatch = /\s+as\s+([A-Za-z_]\w*)\s*$/i.exec(member);
2207
- if (aliasMatch) member = member.slice(0, aliasMatch.index).trim();
2208
- if (!member) continue;
2209
- const module = prefix ? `${prefix}\\${member}` : member;
2210
- const toName = member.split(/[\\/]/).filter(Boolean).pop();
2211
- if (toName) out.push({ toName, callType: "import", module });
2212
- }
2213
- return out.length ? out : null;
2214
- }
2215
- function importFromText(prefixes) {
2216
- return (node) => {
2217
- let text = node.text.replace(/\s+/g, " ").trim();
2218
- for (const prefix of prefixes) {
2219
- if (text.startsWith(prefix)) text = text.slice(prefix.length).trim();
2220
- }
2221
- text = text.replace(
2222
- /^(static|final|type|class|struct|enum|protocol|var|func|let|typealias|function|const)\s+/i,
2223
- ""
2224
- ).trim();
2225
- if (text.includes("{")) return parseGroupedUse(text);
2226
- if (text.includes(",") && !text.includes("<") && !text.includes("=")) {
2227
- const out = [];
2228
- for (const clause of text.split(",")) {
2229
- const one = oneImportClause(clause.trim());
2230
- if (one) out.push(one);
2231
- }
2232
- return out.length ? out : null;
2233
- }
2234
- const single = oneImportClause(text);
2235
- return single ? [single] : null;
2236
- };
2237
- }
2238
- function oneImportClause(rawClause) {
2239
- let text = rawClause;
2240
- text = text.replace(
2241
- /^(static|final|type|class|struct|enum|protocol|var|func|let|typealias|function|const)\s+/i,
2242
- ""
2243
- ).trim();
2244
- text = text.replace(/[;}]+$/g, "").trim();
2245
- const aliasMatch = /\s+as\s+([A-Za-z_]\w*)\s*$/i.exec(text);
2246
- if (aliasMatch) text = text.slice(0, aliasMatch.index).trim();
2247
- const eqMatch = /^([A-Za-z_]\w*)\s*=\s*(.+)$/.exec(text);
2248
- if (eqMatch) text = eqMatch[2].trim();
2249
- if (!text) return null;
2250
- if (text.endsWith("*")) text = text.slice(0, -1).replace(/[.]$/, "");
2251
- if (!text) return null;
2252
- const module = text;
2253
- const toName = module.split(/[.\\/]/).filter(Boolean).pop()?.replace(/<.*>$/s, "");
2254
- if (!toName) return null;
2255
- return { toName, callType: "import", module };
2256
- }
2257
- function heritageLeaf(node, depth) {
2258
- if (depth > 6) return null;
2259
- const named = node.childForFieldName("name");
2260
- if (named) {
2261
- if (named.type === "scoped_type_identifier" || named.type === "qualified_name" || named.type === "scope_resolution" || named.type === "user_type") {
2262
- return heritageLeaf(named, depth + 1);
2263
- }
2264
- return named.text;
2265
- }
2266
- const children = [];
2267
- for (let i = 0; i < node.namedChildCount; i++) {
2268
- const c = node.namedChild(i);
2269
- if (c) children.push(c);
2270
- }
2271
- for (let i = children.length - 1; i >= 0; i--) {
2272
- const c = children[i];
2273
- if (c.type === "type_arguments" || c.type === "type_argument_list" || // cpp: (template_type arguments: (template_argument_list …)) — the
2274
- // descriptor's type_identifier inside it is never the declared base.
2275
- c.type === "template_argument_list" || c.type === "type_parameter_list" || c.type === "type_projection" || c.type === "value_arguments") {
2276
- continue;
2277
- }
2278
- if (c.type === "type_identifier" || c.type === "identifier" || c.type === "constant" || c.type === "name") {
2279
- return c.text;
2280
- }
2281
- if (c.type === "scoped_type_identifier" || c.type === "qualified_name" || c.type === "scope_resolution" || c.type === "user_type") {
2282
- return heritageLeaf(c, depth + 1);
2283
- }
2284
- }
2285
- return leafSegment(
2286
- node.text.replace(/\\/g, ".").replace(/::/g, ".").replace(/<[^<>]*>$/, "")
2287
- );
2288
- }
2289
- function leafSegment(text) {
2290
- return text.split(".").filter(Boolean).pop() ?? text;
2291
- }
2292
- function getQueries(lang) {
2293
- return LANG_QUERIES[lang] ?? DEFAULT_QUERIES;
2294
- }
2295
- function readFirstString(node) {
2296
- if (!node) return null;
2297
- if (node.type === "string_literal" || node.type === "alias") {
2298
- return node.text.replace(/^"|"$/g, "");
2299
- }
2300
- const child = node.namedChild(0);
2301
- return child ? readFirstString(child) : null;
2302
- }
2303
- var heritageExtractor, cCallExtractor, rubyCallExtractor, firstIdentifierCallExtractor, cIncludeExtractor, phpConstructorExtractor, DEFAULT_QUERIES, LANG_QUERIES;
2304
- var init_queries = __esm({
2305
- "src/codebase-index/tree-sitter/queries.ts"() {
2306
- "use strict";
2307
- heritageExtractor = (node) => {
2308
- const out = [];
2309
- const SKIP_SUBTREES = /* @__PURE__ */ new Set([
2310
- "type_arguments",
2311
- "type_argument_list",
2312
- // tree-sitter-cpp names its argument subtree template_argument_list —
2313
- // verified AST: (base_class_clause (template_type name:
2314
- // (type_identifier) arguments: (template_argument_list
2315
- // (type_descriptor type: (type_identifier))))). Without this entry
2316
- // `class D : Base<Foo>` recurses into the descriptor and emits Foo as a
2317
- // phantom inherit ref.
2318
- "template_argument_list",
2319
- "type_parameter_list",
2320
- "type_projection",
2321
- "value_arguments"
2322
- ]);
2323
- const collect = (current, depth) => {
2324
- if (depth > 4) return;
2325
- for (let i = 0; i < current.namedChildCount; i++) {
2326
- const child = current.namedChild(i);
2327
- if (!child) continue;
2328
- if (SKIP_SUBTREES.has(child.type)) continue;
2329
- if (child.type === "type_identifier" || child.type === "identifier" || child.type === "named_type" || child.type === "type" || // PHP heritage carries `name`; Ruby a `constant`.
2330
- child.type === "constant" || child.type === "name") {
2331
- const name = child.type === "named_type" ? leafSegment(child.text) : child.text;
2332
- if (name) out.push({ toName: name });
2333
- continue;
2334
- }
2335
- if (child.type === "generic_type" || child.type === "generic_name") {
2336
- for (let j = 0; j < child.namedChildCount; j++) {
2337
- const inner = child.namedChild(j);
2338
- if (inner && !SKIP_SUBTREES.has(inner.type) && (inner.type === "type_identifier" || inner.type === "identifier" || inner.type === "name")) {
2339
- out.push({ toName: inner.text });
2340
- break;
2341
- }
2342
- }
2343
- continue;
2344
- }
2345
- if (child.type === "qualified_name" || child.type === "scoped_type_identifier" || child.type === "user_type" || child.type === "scope_resolution") {
2346
- const leaf = heritageLeaf(child, 0);
2347
- if (leaf) out.push({ toName: leaf });
2348
- continue;
2349
- }
2350
- collect(child, depth + 1);
2351
- }
2352
- };
2353
- collect(node, 0);
2354
- return out;
2355
- };
2356
- cCallExtractor = (node) => {
2357
- const fn = node.childForFieldName("function");
2358
- if (!fn) return null;
2359
- if (fn.type === "field_expression") {
2360
- const field = fn.childForFieldName("field");
2361
- if (field) return [{ toName: field.text, callType: "call" }];
2362
- const seg = fn.text.split("->").filter(Boolean).pop();
2363
- if (seg) return [{ toName: leafSegment(seg.split(".")[0] ?? seg), callType: "call" }];
2364
- return null;
2365
- }
2366
- if (fn.type === "qualified_identifier") {
2367
- const name = fn.childForFieldName("name");
2368
- if (name) return [{ toName: name.text, callType: "call" }];
2369
- const seg = fn.text.split("::").filter(Boolean).pop();
2370
- if (seg) return [{ toName: seg.split(/[<(]/)[0].trim(), callType: "call" }];
2371
- return null;
2372
- }
2373
- return [{ toName: fn.text.split(/[<(]/)[0].trim(), callType: "call" }];
2374
- };
2375
- rubyCallExtractor = (node) => {
2376
- const emissions = [];
2377
- const method = node.childForFieldName("method");
2378
- if (method) {
2379
- const name = method.text;
2380
- if (name && !name.includes(" ")) emissions.push({ toName: name, callType: "call" });
2381
- if (name === "require" || name === "require_relative") {
2382
- const args = node.childForFieldName("arguments");
2383
- const first = args?.namedChild(0);
2384
- if (first) {
2385
- const raw = first.text.replace(/^['"]|['"]$/g, "");
2386
- const toName = raw.split("/").filter(Boolean).pop();
2387
- if (toName) emissions.push({ toName, callType: "import", module: raw });
2388
- }
2389
- }
2390
- }
2391
- return emissions;
2392
- };
2393
- firstIdentifierCallExtractor = (node) => {
2394
- for (let i = 0; i < node.namedChildCount; i++) {
2395
- const child = node.namedChild(i);
2396
- if (child && (child.type === "simple_identifier" || child.type === "identifier")) {
2397
- return [{ toName: child.text, callType: "call" }];
2398
- }
2399
- }
2400
- const first = node.namedChild(0);
2401
- if (!first) return null;
2402
- const leaf = leafSegment(first.text.split(/[<(]/)[0] ?? first.text);
2403
- if (!leaf) return null;
2404
- return [{ toName: leaf, callType: "call" }];
2405
- };
2406
- cIncludeExtractor = (node) => {
2407
- const raw = node.text.replace(/^#\s*include\s*/i, "").trim();
2408
- const module = raw.replace(/^["'<]|["'>]$/g, "");
2409
- if (!module) return null;
2410
- const toName = module.split("/").pop()?.replace(/\.h$/, "");
2411
- if (!toName) return null;
2412
- return [{ toName, callType: "import", module }];
2413
- };
2414
- phpConstructorExtractor = (node) => {
2415
- for (let i = 0; i < node.namedChildCount; i++) {
2416
- const child = node.namedChild(i);
2417
- if (child && (child.type === "qualified_name" || child.type === "name")) {
2418
- const leaf = child.text.split(/[\\]/).filter(Boolean).pop();
2419
- if (leaf) return [{ toName: leaf, callType: "call" }];
2420
- }
2421
- }
2422
- return null;
2423
- };
2424
- DEFAULT_QUERIES = {
2425
- declKinds: {}
2426
- };
2427
- LANG_QUERIES = {
2428
- // ─── C family ──────────────────────────────────────────────────────────────
2429
- c: {
2430
- declKinds: {
2431
- function_definition: "function",
2432
- declaration: "function",
2433
- // K&R-style `int foo(...)` ambiguous w/ local var; the visitor prefers the function branch when the declarator field is present
2434
- struct_specifier: "struct",
2435
- union_specifier: "struct",
2436
- enum_specifier: "enum",
2437
- type_definition: "type",
2438
- // `typedef … X;`
2439
- preproc_def: "const"
2440
- // `#define NAME …`
2441
- },
2442
- nameField: {
2443
- function_definition: "declarator",
2444
- declaration: "declarator",
2445
- struct_specifier: "name",
2446
- enum_specifier: "name",
2447
- type_definition: "declarator",
2448
- preproc_def: "name"
2449
- },
2450
- scopeNodes: /* @__PURE__ */ new Set([
2451
- "translation_unit",
2452
- "function_definition",
2453
- "struct_specifier",
2454
- "union_specifier",
2455
- "enum_specifier"
2456
- ]),
2457
- refRules: {
2458
- // `obj->run()` and `Cls::stat()` carry structured function fields —
2459
- // cCallExtractor handles all three AST shapes.
2460
- call_expression: { callType: "call", nameExtractor: cCallExtractor },
2461
- preproc_include: { callType: "import", nameExtractor: cIncludeExtractor }
2462
- }
2463
- },
2464
- cpp: {
2465
- declKinds: {
2466
- function_definition: "function",
2467
- template_declaration: "function",
2468
- // `template<typename T> …`
2469
- class_specifier: "class",
2470
- struct_specifier: "struct",
2471
- union_specifier: "struct",
2472
- enum_specifier: "enum",
2473
- namespace_definition: "namespace",
2474
- type_definition: "type"
2475
- },
2476
- nameField: {
2477
- function_definition: "declarator",
2478
- template_declaration: "name",
2479
- class_specifier: "name",
2480
- struct_specifier: "name",
2481
- enum_specifier: "name",
2482
- namespace_definition: "name",
2483
- type_definition: "declarator"
2484
- },
2485
- scopeNodes: /* @__PURE__ */ new Set([
2486
- "translation_unit",
2487
- "function_definition",
2488
- "class_specifier",
2489
- "struct_specifier",
2490
- "union_specifier",
2491
- "enum_specifier",
2492
- "namespace_definition"
2493
- ]),
2494
- refRules: {
2495
- call_expression: { callType: "call", nameExtractor: cCallExtractor },
2496
- preproc_include: { callType: "import", nameExtractor: cIncludeExtractor },
2497
- // `class Foo : public Bar, private Baz` — the base-class clause.
2498
- base_class_clause: { callType: "inherit", nameExtractor: heritageExtractor }
2499
- }
2500
- },
2501
- java: {
2502
- declKinds: {
2503
- class_declaration: "class",
2504
- interface_declaration: "interface",
2505
- enum_declaration: "enum",
2506
- record_declaration: "class",
2507
- annotation_type_declaration: "interface",
2508
- method_declaration: "method",
2509
- constructor_declaration: "method",
2510
- field_declaration: "property"
2511
- },
2512
- nameField: {
2513
- class_declaration: "name",
2514
- interface_declaration: "name",
2515
- enum_declaration: "name",
2516
- record_declaration: "name",
2517
- annotation_type_declaration: "name",
2518
- method_declaration: "name",
2519
- constructor_declaration: "name"
2520
- },
2521
- // `field_declaration` has no single `name` field — it carries a list of
2522
- // variable declarators. We emit one Symbol per node using the first
2523
- // identifier-shaped named child (see `extractName` fallback in
2524
- // `visitor.ts`). `int a, b, c;` therefore indexes only `a` — splitting
2525
- // multi-declarator fields into separate Symbols is a separate refactor
2526
- // that needs the visitor to know it has multiple names per node, and no
2527
- // current test relies on it.
2528
- scopeNodes: /* @__PURE__ */ new Set([
2529
- "program",
2530
- "class_declaration",
2531
- "interface_declaration",
2532
- "enum_declaration",
2533
- "record_declaration"
2534
- ]),
2535
- refRules: {
2536
- method_invocation: { callType: "call", field: "name" },
2537
- object_creation_expression: { callType: "call", field: "type" },
2538
- // Verified AST: `superclass: (superclass (type_identifier))` and
2539
- // `interfaces: (super_interfaces (type_list ...))` — no underscores.
2540
- superclass: { callType: "inherit", nameExtractor: heritageExtractor },
2541
- super_interfaces: {
2542
- callType: "implement",
2543
- nameExtractor: heritageExtractor
2544
- },
2545
- import_declaration: {
2546
- callType: "import",
2547
- nameExtractor: importFromText(["import "])
2548
- }
2549
- }
2550
- },
2551
- csharp: {
2552
- // C# 10+ `namespace Foo.Bar;` produces this node type. The legacy block
2553
- // form `namespace Foo.Bar { ... }` produces `namespace_declaration`. Both
2554
- // carry a `qualified_name` child whose text already includes the dots.
2555
- // `using_directive` is intentionally not a declaration. Imports are
2556
- // extracted separately; indexing a using directive as a namespace makes
2557
- // the resolver bind it to its own source file before the real declaration.
2558
- declKinds: {
2559
- file_scoped_namespace_declaration: "namespace",
2560
- class_declaration: "class",
2561
- interface_declaration: "interface",
2562
- struct_declaration: "struct",
2563
- enum_declaration: "enum",
2564
- record_declaration: "class",
2565
- method_declaration: "method",
2566
- constructor_declaration: "method",
2567
- property_declaration: "property",
2568
- field_declaration: "property",
2569
- namespace_declaration: "namespace"
2570
- },
2571
- // Custom name extractor: take the full dotted name verbatim.
2572
- nameExtractor: (node) => {
2573
- const inner = node.namedChild(0);
2574
- if (inner && (inner.type === "qualified_name" || inner.type === "name")) {
2575
- return inner.text;
2576
- }
2577
- return null;
2578
- },
2579
- scopeNodes: /* @__PURE__ */ new Set([
2580
- "compilation_unit",
2581
- "namespace_declaration",
2582
- "class_declaration",
2583
- "interface_declaration",
2584
- "struct_declaration",
2585
- "enum_declaration",
2586
- "record_declaration"
2587
- ]),
2588
- refRules: {
2589
- // Verified AST: `invocation_expression function: (identifier)` — the
2590
- // callee field is `function` (C-style), not `name`.
2591
- invocation_expression: { callType: "call", field: "function" },
2592
- object_creation_expression: { callType: "call", field: "type" },
2593
- base_list: { callType: "inherit", nameExtractor: heritageExtractor },
2594
- using_directive: {
2595
- callType: "import",
2596
- nameExtractor: importFromText(["using "])
2597
- }
2598
- }
2599
- },
2600
- php: {
2601
- declKinds: {
2602
- function_definition: "function",
2603
- method_declaration: "method",
2604
- class_declaration: "class",
2605
- interface_declaration: "interface",
2606
- trait_declaration: "class",
2607
- enum_declaration: "enum",
2608
- namespace_definition: "namespace"
2609
- },
2610
- nameField: {
2611
- function_definition: "name",
2612
- method_declaration: "name",
2613
- class_declaration: "name",
2614
- interface_declaration: "name",
2615
- trait_declaration: "name",
2616
- enum_declaration: "name",
2617
- namespace_definition: "name"
2618
- },
2619
- scopeNodes: /* @__PURE__ */ new Set([
2620
- "program",
2621
- "namespace_definition",
2622
- "class_declaration",
2623
- "interface_declaration",
2624
- "trait_declaration",
2625
- "enum_declaration"
2626
- ]),
2627
- refRules: {
2628
- function_call_expression: { callType: "call", field: "function" },
2629
- // Verified AST: `new App\Model\User()` carries a BARE qualified_name
2630
- // child (no `name:` field), so the field default never fires.
2631
- object_creation_expression: { callType: "call", nameExtractor: phpConstructorExtractor },
2632
- base_clause: { callType: "inherit", nameExtractor: heritageExtractor },
2633
- class_interface_clause: {
2634
- callType: "implement",
2635
- nameExtractor: heritageExtractor
2636
- },
2637
- // Verified AST: `namespace_use_declaration (namespace_use_clause
2638
- // (qualified_name ...))` — not `use_declaration`.
2639
- namespace_use_declaration: {
2640
- callType: "import",
2641
- nameExtractor: importFromText(["use "])
2642
- }
2643
- }
2644
- },
2645
- // ─── Scripting / mobile ────────────────────────────────────────────────────
2646
- ruby: {
2647
- declKinds: {
2648
- method: "function",
2649
- singleton_method: "method",
2650
- class: "class",
2651
- module: "namespace",
2652
- constant: "const"
2653
- },
2654
- nameField: {
2655
- method: "name",
2656
- singleton_method: "name",
2657
- class: "name",
2658
- module: "name",
2659
- constant: "name"
2660
- },
2661
- scopeNodes: /* @__PURE__ */ new Set(["program", "class", "module", "singleton_method", "method"]),
2662
- refRules: {
2663
- // `call` covers both `foo(...)` and `obj.foo(...)` — the extractor
2664
- // records the method leaf, plus `require`/`require_relative` imports.
2665
- call: { callType: "call", nameExtractor: rubyCallExtractor },
2666
- superclass: { callType: "inherit", nameExtractor: heritageExtractor }
2667
- }
2668
- },
2669
- swift: {
2670
- declKinds: {
2671
- function_declaration: "function",
2672
- class_declaration: "class",
2673
- struct_declaration: "struct",
2674
- enum_declaration: "enum",
2675
- protocol_declaration: "interface",
2676
- actor_declaration: "class",
2677
- extension_declaration: "class",
2678
- initializer: "method",
2679
- property_declaration: "property"
2680
- },
2681
- nameField: {
2682
- function_declaration: "name",
2683
- class_declaration: "name",
2684
- struct_declaration: "name",
2685
- enum_declaration: "name",
2686
- protocol_declaration: "name",
2687
- actor_declaration: "name",
2688
- extension_declaration: "name",
2689
- initializer: "name",
2690
- property_declaration: "name"
2691
- },
2692
- scopeNodes: /* @__PURE__ */ new Set([
2693
- "source_file",
2694
- "class_declaration",
2695
- "struct_declaration",
2696
- "enum_declaration",
2697
- "protocol_declaration",
2698
- "actor_declaration",
2699
- "extension_declaration"
2700
- ]),
2701
- refRules: {
2702
- // Verified AST: `call_expression (simple_identifier) (call_suffix …)` —
2703
- // the callee is a bare first child, no field name.
2704
- call_expression: { callType: "call", nameExtractor: firstIdentifierCallExtractor },
2705
- // Verified AST: `inheritance_specifier inherits_from: (user_type …)`.
2706
- inheritance_specifier: { callType: "inherit", nameExtractor: heritageExtractor },
2707
- import_declaration: {
2708
- callType: "import",
2709
- nameExtractor: importFromText(["import ", "import type ", "@testable import "])
2710
- }
2711
- }
2712
- },
2713
- kotlin: {
2714
- declKinds: {
2715
- class_declaration: "class",
2716
- object_declaration: "class",
2717
- interface_declaration: "interface",
2718
- function_declaration: "function",
2719
- property_declaration: "property",
2720
- type_alias: "type"
2721
- },
2722
- nameField: {
2723
- class_declaration: "name",
2724
- object_declaration: "name",
2725
- interface_declaration: "name",
2726
- function_declaration: "name",
2727
- property_declaration: "name",
2728
- type_alias: "name"
2729
- },
2730
- scopeNodes: /* @__PURE__ */ new Set([
2731
- "source_file",
2732
- "class_declaration",
2733
- "object_declaration",
2734
- "interface_declaration",
2735
- "function_declaration"
2736
- ]),
2737
- refRules: {
2738
- call_expression: { callType: "call", nameExtractor: firstIdentifierCallExtractor },
2739
- // Verified AST: `delegation_specifier (user_type (type_identifier))` —
2740
- // the `: Handler` / `: Base()` clause.
2741
- delegation_specifier: { callType: "inherit", nameExtractor: heritageExtractor },
2742
- import_header: {
2743
- callType: "import",
2744
- nameExtractor: importFromText(["import "])
2745
- }
2746
- }
2747
- },
2748
- elixir: {
2749
- declKinds: {
2750
- // `def foo`, `defp foo`, `defmacro foo`, `macrop foo` all surface as
2751
- // `call` nodes in the tree-sitter grammar — there is no
2752
- // `function_definition`. The `nameExtractor` walks the call's
2753
- // children to pick the right sibling identifier.
2754
- call: "function",
2755
- module: "namespace"
2756
- },
2757
- nameExtractor: (node) => {
2758
- if (node.type === "module") {
2759
- const aliasNode = node.childForFieldName("alias");
2760
- return readFirstString(aliasNode) ?? null;
2761
- }
2762
- if (node.type !== "call") return null;
2763
- const first = node.namedChild(0);
2764
- if (!first) return null;
2765
- const target = first.text;
2766
- if (target !== "def" && target !== "defp" && target !== "defmacro" && target !== "defp_macro" && target !== "macrop" && target !== "defprotocol" && target !== "defguard" && target !== "defguardp") {
2767
- return null;
2768
- }
2769
- const nameNode = node.namedChild(1);
2770
- return nameNode?.text ?? null;
2771
- },
2772
- scopeNodes: /* @__PURE__ */ new Set(["source", "module"])
2773
- },
2774
- shell: {
2775
- declKinds: {
2776
- function_definition: "function"
2777
- },
2778
- nameField: { function_definition: "name" },
2779
- scopeNodes: /* @__PURE__ */ new Set(["program", "function_definition"])
2780
- }
2781
- };
2782
- }
2783
- });
2784
-
2785
- // src/codebase-index/tree-sitter/util.ts
2786
- function lineColAt2(offsets, index) {
2787
- let low = 0;
2788
- let high = offsets.length;
2789
- while (low < high) {
2790
- const mid = low + high >>> 1;
2791
- if ((offsets[mid] ?? 0) < index) low = mid + 1;
2792
- else high = mid;
2793
- }
2794
- const lastNl = low > 0 ? offsets[low - 1] ?? -1 : -1;
2795
- return { line: low + 1, col: index - lastNl };
2796
- }
2797
- function newlineOffsets3(content) {
2798
- const offsets = [];
2799
- for (let i = 0; i < content.length; i++) {
2800
- if (content.charCodeAt(i) === 10) offsets.push(i);
2801
- }
2802
- return offsets;
2803
- }
2804
- var TREE_SITTER_MAX_FILE_CHARS, TREE_SITTER_MAX_SYMBOLS;
2805
- var init_util = __esm({
2806
- "src/codebase-index/tree-sitter/util.ts"() {
2807
- "use strict";
2808
- TREE_SITTER_MAX_FILE_CHARS = 512 * 1024;
2809
- TREE_SITTER_MAX_SYMBOLS = 500;
2810
- }
2811
- });
2812
-
2813
- // src/codebase-index/tree-sitter/visitor.ts
2814
- function visitTree(tree, content, file, lang, queries) {
2815
- const boundedContent = content.length > TREE_SITTER_MAX_FILE_CHARS ? content.slice(0, TREE_SITTER_MAX_FILE_CHARS) : content;
2816
- const nlOffsets = newlineOffsets3(boundedContent);
2817
- const symbols = [];
2818
- const refs = [];
2819
- const seenRefs = /* @__PURE__ */ new Set();
2820
- const scopeStack = [];
2821
- function emitRefsForNode(node, rule) {
2822
- const emissions = rule.nameExtractor?.(node) ?? defaultRefTarget(node, rule);
2823
- if (!emissions) return;
2824
- const { line } = lineColAt2(nlOffsets, node.startIndex);
2825
- for (const emission of emissions) {
2826
- if (!emission.toName) continue;
2827
- const callType = emission.callType ?? rule.callType;
2828
- const key = `${emission.toName}:${callType}:${line}:${emission.module ?? ""}:${node.startIndex}`;
2829
- if (seenRefs.has(key)) continue;
2830
- seenRefs.add(key);
2831
- refs.push({
2832
- fromId: 0,
2833
- // assignRefsToSymbols attaches owners after insertion
2834
- toName: emission.toName.slice(0, 200),
2835
- callType,
2836
- line,
2837
- lang,
2838
- module: emission.module
2839
- });
2840
- }
2841
- }
2842
- function defaultRefTarget(node, rule) {
2843
- if (!rule.field) return null;
2844
- const field = node.childForFieldName(rule.field);
2845
- if (!field) return null;
2846
- const leaf = field.text.split(/[.:\\]/).filter(Boolean).pop()?.split(/[<(]/)[0];
2847
- if (!leaf) return null;
2848
- return [{ toName: leaf.trim() }];
2849
- }
2850
- function visit(node, depth) {
2851
- if (symbols.length >= TREE_SITTER_MAX_SYMBOLS) return;
2852
- if (node.isMissing || node.isError) {
2853
- } else {
2854
- const kind = queries.declKinds[node.type];
2855
- if (kind) {
2856
- const emitted = emitSymbol(
2857
- node,
2858
- kind,
2859
- file,
2860
- lang,
2861
- scopeStack,
2862
- boundedContent,
2863
- nlOffsets,
2864
- queries
2865
- );
2866
- if (emitted) symbols.push(emitted);
2867
- }
2868
- const refRule = queries.refRules?.[node.type];
2869
- if (refRule) emitRefsForNode(node, refRule);
2870
- }
2871
- const pushesScope = queries.scopeNodes?.has(node.type) ?? false;
2872
- const pushIdx = pushesScope ? pushScope(scopeStack, node, queries) : -1;
2873
- if (queries.skipNamedChildren) {
2874
- if (pushIdx !== -1) scopeStack.pop();
2875
- return;
2876
- }
2877
- for (const child of node.namedChildren) {
2878
- visit(child, depth + 1);
2879
- if (symbols.length >= TREE_SITTER_MAX_SYMBOLS) {
2880
- if (pushIdx !== -1) scopeStack.pop();
2881
- return;
2882
- }
2883
- }
2884
- if (pushIdx !== -1) scopeStack.pop();
2885
- }
2886
- visit(tree.rootNode, 0);
2887
- return { symbols, refs };
2888
- }
2889
- function pushScope(scopeStack, node, queries) {
2890
- const name = extractName(node, queries);
2891
- if (!name) return -1;
2892
- scopeStack.push(name);
2893
- return scopeStack.length - 1;
2894
- }
2895
- function extractName(node, queries) {
2896
- if (queries.nameExtractor) {
2897
- const extracted = queries.nameExtractor(node);
2898
- if (extracted) return extracted;
2899
- }
2900
- const fieldName = queries.nameField?.[node.type] ?? "name";
2901
- const field = node.childForFieldName(fieldName);
2902
- if (field) {
2903
- if (IDENTIFIER_NODE_TYPES.has(field.type)) {
2904
- return field.text;
2905
- }
2906
- const inner = field.childForFieldName("name") ?? field.namedChild(0);
2907
- if (inner && IDENTIFIER_NODE_TYPES.has(inner.type)) {
2908
- return inner.text;
2909
- }
2910
- }
2911
- for (let i = 0; i < node.namedChildCount; i++) {
2912
- const child = node.namedChild(i);
2913
- if (child && IDENTIFIER_NODE_TYPES.has(child.type)) {
2914
- return child.text;
2915
- }
2916
- }
2917
- return null;
2918
- }
2919
- function emitSymbol(node, kind, file, lang, scopeStack, content, nlOffsets, queries) {
2920
- const name = extractName(node, queries);
2921
- if (!name) return null;
2922
- const pos = node.startIndex;
2923
- const { line, col } = lineColAt2(nlOffsets, pos);
2924
- const end = Math.min(node.endIndex, content.length);
2925
- const signature = content.slice(pos, end).replace(/\s+/g, " ").trim().slice(0, 500);
2926
- const scope = scopeStack.join(".");
2927
- const text = [name, signature].filter(Boolean).join(" | ").trim().slice(0, 1e3);
2928
- return {
2929
- id: 0,
2930
- // caller assigns during bulk insertion
2931
- lang,
2932
- kind,
2933
- name: name.slice(0, 200),
2934
- file,
2935
- line,
2936
- col,
2937
- signature,
2938
- docComment: "",
2939
- // doc-comment extraction lands with ref emission on Day 4
2940
- scope,
2941
- text
2942
- };
2943
- }
2944
- var IDENTIFIER_NODE_TYPES;
2945
- var init_visitor = __esm({
2946
- "src/codebase-index/tree-sitter/visitor.ts"() {
2947
- "use strict";
2948
- init_util();
2949
- IDENTIFIER_NODE_TYPES = /* @__PURE__ */ new Set([
2950
- "identifier",
2951
- "simple_identifier",
2952
- "type_identifier",
2953
- "field_identifier",
2954
- "property_identifier",
2955
- "name",
2956
- "word",
2957
- "variable_name",
2958
- "constant",
2959
- "sym"
2960
- ]);
2961
- }
2962
- });
2963
-
2964
- // src/codebase-index/tree-sitter-parser.ts
2965
- var tree_sitter_parser_exports = {};
2966
- __export(tree_sitter_parser_exports, {
2967
- __smokeRootType: () => __smokeRootType,
2968
- getGrammarWasmPath: () => getGrammarWasmPath,
2969
- isTreeSitterSupported: () => isTreeSitterSupported,
2970
- loadTreeSitterLanguage: () => loadTreeSitterLanguage,
2971
- parseSymbols: () => parseSymbols8,
2972
- parseTreeSitterAst: () => parseTreeSitterAst
2973
- });
2974
- import * as path7 from "node:path";
2975
- import { fileURLToPath } from "node:url";
2976
- function optInEnabled(env) {
2977
- return process.env[env] === "1" || process.env[env] === "true";
2978
- }
2979
- function getRuntime() {
2980
- if (!runtimePromise) {
2981
- runtimePromise = (async () => {
2982
- const mod = await import("web-tree-sitter");
2983
- const init = () => mod.Parser.init({ locateFile: () => RUNTIME_WASM });
2984
- return { Parser: mod.Parser, Language: mod.Language, init };
2985
- })();
2986
- }
2987
- return runtimePromise;
2988
- }
2989
- async function loadLanguage(lang) {
2990
- const existing = languageCache.get(lang);
2991
- if (existing) return existing;
2992
- const promise = (async () => {
2993
- const grammarName = resolveGrammarName(lang);
2994
- if (!grammarName) {
2995
- throw new Error(`tree-sitter: no grammar registered for lang "${lang}"`);
2996
- }
2997
- const wasmPath = path7.join(WASM_DIR, grammarName, `tree-sitter-${grammarName}.wasm`);
2998
- const { Language, init } = await getRuntime();
2999
- await init();
3000
- const languageObj = await Language.load(wasmPath);
3001
- return { lang, Language: languageObj };
3002
- })();
3003
- languageCache.set(lang, promise);
3004
- return promise;
3005
- }
3006
- function resolveGrammarName(lang) {
3007
- if (lang === "go" && optInEnabled(GO_OPT_IN)) return "go";
3008
- if (lang === "py" && optInEnabled(PY_OPT_IN)) return "python";
3009
- if (lang === "rs" && optInEnabled(RS_OPT_IN)) return "rust";
3010
- return LANG_TO_GRAMMAR[lang];
3011
- }
3012
- function isTreeSitterSupported(lang) {
3013
- return resolveGrammarName(lang) !== void 0;
3014
- }
3015
- function getGrammarWasmPath(lang) {
3016
- const name = resolveGrammarName(lang);
3017
- if (!name) return void 0;
3018
- return path7.join(WASM_DIR, name, `tree-sitter-${name}.wasm`);
3019
- }
3020
- async function parseSymbols8(opts) {
3021
- const { file, content, lang } = opts;
3022
- if (!isTreeSitterSupported(lang)) {
3023
- return { file, lang, symbols: [], mtimeMs: Date.now() };
3024
- }
3025
- try {
3026
- const { Parser } = await getRuntime();
3027
- const cached = await loadLanguage(lang);
3028
- const parser = new Parser();
3029
- parser.setLanguage(cached.Language);
3030
- const tree = parser.parse(content);
3031
- if (!tree) {
3032
- return { file, lang, symbols: [], mtimeMs: Date.now() };
3033
- }
3034
- const { symbols, refs } = visitTree(tree, content, file, lang, getQueries(lang));
3035
- parser.delete();
3036
- tree.delete();
3037
- return { file, lang, symbols, refs, mtimeMs: Date.now() };
3038
- } catch {
3039
- return { file, lang, symbols: [], mtimeMs: Date.now() };
3040
- }
3041
- }
3042
- async function loadTreeSitterLanguage(lang) {
3043
- const cached = await loadLanguage(lang);
3044
- return cached.Language;
3045
- }
3046
- async function __smokeRootType(opts) {
3047
- if (!isTreeSitterSupported(opts.lang)) {
3048
- throw new Error(`tree-sitter: no grammar registered for lang "${opts.lang}"`);
3049
- }
3050
- const { Parser } = await getRuntime();
3051
- const cached = await loadLanguage(opts.lang);
3052
- const parser = new Parser();
3053
- parser.setLanguage(cached.Language);
3054
- let tree = null;
3055
- try {
3056
- tree = parser.parse(opts.content);
3057
- if (!tree) throw new Error("tree-sitter: parser.parse returned null");
3058
- return tree.rootNode.type;
3059
- } finally {
3060
- tree?.delete();
3061
- parser.delete();
3062
- }
3063
- }
3064
- async function parseTreeSitterAst(opts) {
3065
- const grammar = resolveGrammarName(opts.lang) ?? (opts.lang === "go" ? "go" : opts.lang === "py" ? "python" : opts.lang === "rs" ? "rust" : void 0);
3066
- if (!grammar) return null;
3067
- try {
3068
- const { Parser, Language, init } = await getRuntime();
3069
- await init();
3070
- const wasmPath = path7.join(WASM_DIR, grammar, `tree-sitter-${grammar}.wasm`);
3071
- const languageObj = await Language.load(wasmPath);
3072
- const parser = new Parser();
3073
- parser.setLanguage(languageObj);
3074
- const tree = parser.parse(opts.content);
3075
- if (!tree) {
3076
- parser.delete();
3077
- return null;
3078
- }
3079
- return { tree, parser };
3080
- } catch {
3081
- return null;
3082
- }
3083
- }
3084
- var WASM_DIR, RUNTIME_WASM, LANG_TO_GRAMMAR, GO_OPT_IN, PY_OPT_IN, RS_OPT_IN, runtimePromise, languageCache;
3085
- var init_tree_sitter_parser = __esm({
3086
- "src/codebase-index/tree-sitter-parser.ts"() {
3087
- "use strict";
3088
- init_queries();
3089
- init_visitor();
3090
- WASM_DIR = fileURLToPath(new URL("./wasm/", import.meta.url));
3091
- RUNTIME_WASM = path7.join(WASM_DIR, "tree-sitter-runtime.wasm");
3092
- LANG_TO_GRAMMAR = {
3093
- c: "c",
3094
- cpp: "cpp",
3095
- java: "java",
3096
- csharp: "c_sharp",
3097
- // tree-sitter directory uses underscore
3098
- php: "php",
3099
- ruby: "ruby",
3100
- swift: "swift",
3101
- kotlin: "kotlin",
3102
- shell: "bash",
3103
- // we treat `.sh` / `.bash` / `.zsh` via the bash grammar
3104
- // Go/Python/Rust are opt-in only (see goOptIn / pyOptIn / rsOptIn below)
3105
- elixir: "elixir"
3106
- };
3107
- GO_OPT_IN = "WRONGSTACK_USE_TS_GO";
3108
- PY_OPT_IN = "WRONGSTACK_USE_TS_PY";
3109
- RS_OPT_IN = "WRONGSTACK_USE_TS_RS";
3110
- runtimePromise = null;
3111
- languageCache = /* @__PURE__ */ new Map();
3112
- }
3113
- });
1
+ import {
2
+ parseFilesContent
3
+ } from "../chunk-IYK7XGDZ.js";
4
+ import "../chunk-ZLTFLC25.js";
5
+ import "../chunk-A6BRWIXN.js";
6
+ import "../chunk-UCYQTZ7F.js";
7
+ import "../chunk-TEBQ4VPZ.js";
8
+ import "../chunk-V43EQ6VR.js";
3114
9
 
3115
10
  // src/codebase-index/parser-worker-script.ts
3116
11
  import { parentPort, threadId } from "node:worker_threads";
3117
-
3118
- // src/codebase-index/import-extractor.ts
3119
- var IMPORT_MAX_FILE_CHARS = 512 * 1024;
3120
- var IMPORT_MAX_PER_FILE = 400;
3121
- var DOTTED_IMPORT = [
3122
- { re: /^[ \t]*import\s+(?:static\s+)?([\w.]+(?:\.\*)?)\s*;?\s*$/gm }
3123
- ];
3124
- var LANG_IMPORTS = {
3125
- // Go and Python have real AST extractors; these patterns are the fallback for
3126
- // machines with no Go toolchain or Python interpreter installed, where the
3127
- // parser degrades to regex symbols and would otherwise contribute no edges.
3128
- go: [
3129
- { re: /^[ \t]*import\s+(?:[\w.]+\s+)?"([^"]+)"/gm },
3130
- // Grouped form: inside `import ( … )` each line is an optional alias plus a
3131
- // quoted path. A stray match elsewhere resolves to no file and is dropped.
3132
- { re: /^[ \t]*(?:[A-Za-z_.]\w*\s+)?"([^"]+)"\s*$/gm }
3133
- ],
3134
- py: [{ re: /^[ \t]*import\s+([\w.]+)/gm }, { re: /^[ \t]*from\s+([.\w]+)\s+import\b/gm }],
3135
- rs: [
3136
- // use a::b::C; | use a::b::{C, D}; → the path before any brace
3137
- { re: /^[ \t]*(?:pub\s+)?use\s+([\w:]+?)(?:::\{|\s*;|\s+as\b)/gm },
3138
- // mod foo; (a declaration *and* a dependency on foo.rs / foo/mod.rs)
3139
- { re: /^[ \t]*(?:pub\s+)?mod\s+(\w+)\s*;/gm }
3140
- ],
3141
- java: DOTTED_IMPORT,
3142
- kotlin: DOTTED_IMPORT,
3143
- scala: [{ re: /^[ \t]*import\s+([\w.]+(?:\.[_*])?)\s*$/gm }],
3144
- csharp: [
3145
- // using Foo.Bar; | using static Foo.Bar; | using Alias = Foo.Bar;
3146
- { re: /^[ \t]*global\s+using\s+(?:static\s+)?([\w.]+)\s*;/gm, name: "full" },
3147
- { re: /^[ \t]*using\s+(?:static\s+)?(?:\w+\s*=\s*)?([\w.]+)\s*;/gm, name: "full" }
3148
- ],
3149
- // Quoted includes only: <stdio.h> is a system header with no indexed file.
3150
- c: [{ re: /^[ \t]*#\s*include\s+"([^"]+)"/gm }],
3151
- cpp: [{ re: /^[ \t]*#\s*include\s+"([^"]+)"/gm }],
3152
- ruby: [{ re: /^[ \t]*(?:require|require_relative|load)\s*\(?\s*['"]([^'"]+)['"]/gm }],
3153
- php: [
3154
- // `use A\B\C` imports the class C, which is what the index has a symbol
3155
- // for — the namespace symbol only covers the `A\B` prefix.
3156
- { re: /^[ \t]*use\s+(?:function\s+|const\s+)?([\w\\]+)/gm },
3157
- { re: /^[ \t]*(?:require|require_once|include|include_once)\s*\(?\s*['"]([^'"]+)['"]/gm }
3158
- ],
3159
- swift: [{ re: /^[ \t]*import\s+(?:struct\s+|class\s+|func\s+)?([\w.]+)\s*$/gm }],
3160
- dart: [{ re: /^[ \t]*(?:import|export|part)\s+['"]([^'"]+)['"]/gm }],
3161
- lua: [{ re: /\brequire\s*\(?\s*['"]([^'"]+)['"]/g }],
3162
- elixir: [{ re: /^[ \t]*(?:alias|import|require|use)\s+([A-Z][\w.]*)/gm, name: "full" }],
3163
- haskell: [{ re: /^[ \t]*import\s+(?:qualified\s+)?([\w.]+)/gm, name: "full" }],
3164
- zig: [{ re: /@import\s*\(\s*"([^"]+)"\s*\)/g }],
3165
- proto: [{ re: /^[ \t]*import\s+(?:public\s+|weak\s+)?"([^"]+)"\s*;/gm }],
3166
- // `@import "x"`, `@use "x"`, `@forward "x"` — Sass and plain CSS alike.
3167
- css: [{ re: /^[ \t]*@(?:import|use|forward)\s+(?:url\()?\s*['"]([^'"]+)['"]/gm }],
3168
- // A .vue/.svelte file's <script> block is JS; the same ESM syntax applies.
3169
- vue: [{ re: /^[ \t]*import\s[^'"]*from\s*['"]([^'"]+)['"]/gm }],
3170
- svelte: [{ re: /^[ \t]*import\s[^'"]*from\s*['"]([^'"]+)['"]/gm }],
3171
- html: [
3172
- { re: /<script[^>]+src\s*=\s*['"]([^'"]+)['"]/g },
3173
- { re: /<link[^>]+href\s*=\s*['"]([^'"]+)['"]/g }
3174
- ],
3175
- shell: [{ re: /^[ \t]*(?:source|\.)\s+(\S+)/gm }],
3176
- r: [{ re: /\b(?:source|library|require)\s*\(\s*['"]?([\w./-]+)['"]?\s*\)/g }]
3177
- };
3178
- function lastSegment(specifier) {
3179
- const pathLike = /[/\\]|::/.test(specifier);
3180
- const segments = specifier.split(/[/\\]|::/).filter(Boolean);
3181
- let last = segments[segments.length - 1] ?? specifier;
3182
- if (last === "*" || last === "_") {
3183
- last = segments[segments.length - 2] ?? specifier;
3184
- }
3185
- if (pathLike) return last.replace(/\.[A-Za-z0-9]{1,8}$/, "") || last;
3186
- const dotted = last.split(".").filter((part) => part && part !== "*" && part !== "_");
3187
- return dotted[dotted.length - 1] ?? last;
3188
- }
3189
- function newlineOffsets(content) {
3190
- const offsets = [];
3191
- for (let i = 0; i < content.length; i++) {
3192
- if (content.charCodeAt(i) === 10) offsets.push(i);
3193
- }
3194
- return offsets;
3195
- }
3196
- function lineAt(offsets, index) {
3197
- let low = 0;
3198
- let high = offsets.length;
3199
- while (low < high) {
3200
- const mid = low + high >>> 1;
3201
- if ((offsets[mid] ?? 0) < index) low = mid + 1;
3202
- else high = mid;
3203
- }
3204
- return low + 1;
3205
- }
3206
- function hasImportPatterns(lang) {
3207
- return LANG_IMPORTS[lang] !== void 0;
3208
- }
3209
- function extractImports(opts) {
3210
- const patterns = LANG_IMPORTS[opts.lang];
3211
- if (!patterns || !opts.content) return [];
3212
- const limit = opts.maxImports ?? IMPORT_MAX_PER_FILE;
3213
- const content = opts.content.length > IMPORT_MAX_FILE_CHARS ? opts.content.slice(0, IMPORT_MAX_FILE_CHARS) : opts.content;
3214
- const refs = [];
3215
- const seen = /* @__PURE__ */ new Set();
3216
- const offsets = newlineOffsets(content);
3217
- for (const pattern of patterns) {
3218
- const re = new RegExp(pattern.re.source, pattern.re.flags);
3219
- for (const match of content.matchAll(re)) {
3220
- if (refs.length >= limit) return refs;
3221
- const specifier = match[1]?.trim();
3222
- if (!specifier) continue;
3223
- const module = specifier;
3224
- const toName = pattern.name === "full" ? module : lastSegment(module);
3225
- if (!toName) continue;
3226
- const key = `${module}\0${toName}`;
3227
- if (seen.has(key)) continue;
3228
- seen.add(key);
3229
- refs.push({
3230
- fromId: 0,
3231
- toName,
3232
- callType: "import",
3233
- line: lineAt(offsets, match.index ?? 0),
3234
- lang: opts.lang,
3235
- module
3236
- });
3237
- }
3238
- }
3239
- return refs;
3240
- }
3241
-
3242
- // src/codebase-index/parser-batch.ts
3243
- init_win32_resolve();
3244
- init_parser_output();
3245
- init_spawn_gate();
3246
- import { spawn } from "node:child_process";
3247
- import * as fsSync from "node:fs";
3248
- import * as fs2 from "node:fs/promises";
3249
- import * as os from "node:os";
3250
- import * as path2 from "node:path";
3251
- var MAX_BATCH_FILES = 100;
3252
- var MAX_BATCH_BYTES = 8 * 1024 * 1024;
3253
- function chunkBatchFiles(files) {
3254
- const chunks = [];
3255
- let current = [];
3256
- let bytes = 0;
3257
- for (const file of files) {
3258
- const size = Buffer.byteLength(file.content, "utf8");
3259
- if (current.length > 0 && (current.length >= MAX_BATCH_FILES || bytes + size > MAX_BATCH_BYTES)) {
3260
- chunks.push(current);
3261
- current = [];
3262
- bytes = 0;
3263
- }
3264
- current.push(file);
3265
- bytes += size;
3266
- }
3267
- if (current.length > 0) chunks.push(current);
3268
- return chunks;
3269
- }
3270
- function batchTimeoutMs(fileCount) {
3271
- return Math.min(12e4, 15e3 + fileCount * 1500);
3272
- }
3273
- var GO_BATCH_SCRIPT = `
3274
- package main
3275
-
3276
- import (
3277
- "encoding/json"
3278
- "fmt"
3279
- "go/ast"
3280
- "go/parser"
3281
- "go/token"
3282
- "io"
3283
- "os"
3284
- "strconv"
3285
- "strings"
3286
- )
3287
-
3288
- type Sym struct {
3289
- Name string \`json:"name"\`
3290
- Kind string \`json:"kind"\`
3291
- Line int \`json:"line"\`
3292
- Col int \`json:"col"\`
3293
- Signature string \`json:"signature"\`
3294
- Scope string \`json:"scope"\`
3295
- }
3296
-
3297
- type Ref struct {
3298
- ToName string \`json:"toName"\`
3299
- CallType string \`json:"callType"\`
3300
- Line int \`json:"line"\`
3301
- Module string \`json:"module"\`
3302
- }
3303
-
3304
- type FileResult struct {
3305
- File string \`json:"file"\`
3306
- Error string \`json:"error,omitempty"\`
3307
- Symbols []Sym \`json:"symbols"\`
3308
- Refs []Ref \`json:"refs"\`
3309
- }
3310
-
3311
- type BatchResult struct {
3312
- Version int \`json:"version"\`
3313
- Results []FileResult \`json:"results"\`
3314
- }
3315
-
3316
- type inputFile struct {
3317
- File string \`json:"file"\`
3318
- Content string \`json:"content"\`
3319
- }
3320
-
3321
- func parseOne(name string, src []byte) FileResult {
3322
- res := FileResult{File: name, Symbols: []Sym{}, Refs: []Ref{}}
3323
- fset := token.NewFileSet()
3324
- node, err := parser.ParseFile(fset, "src.go", src, 0)
3325
- if err != nil {
3326
- res.Error = err.Error()
3327
- return res
3328
- }
3329
- pkgScope := node.Name.Name
3330
- for _, decl := range node.Decls {
3331
- switch d := decl.(type) {
3332
- case *ast.FuncDecl:
3333
- symName := d.Name.Name
3334
- kind := "function"
3335
- scope := pkgScope
3336
- if d.Recv != nil && len(d.Recv.List) > 0 {
3337
- scope = pkgScope + "." + recvTypeName(d.Recv.List[0].Type) + "." + symName
3338
- kind = "method"
3339
- } else {
3340
- scope = pkgScope + "." + symName
3341
- }
3342
- pos := fset.Position(d.Pos())
3343
- res.Symbols = append(res.Symbols, Sym{Name: symName, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: formatFuncSig(d), Scope: scope})
3344
- case *ast.GenDecl:
3345
- for _, spec := range d.Specs {
3346
- switch s := spec.(type) {
3347
- case *ast.TypeSpec:
3348
- typeName := s.Name.Name
3349
- pos := fset.Position(s.Pos())
3350
- sig := "type " + typeName
3351
- if s.TypeParams != nil {
3352
- sig += formatTypeParams(s.TypeParams)
3353
- }
3354
- if st, ok := s.Type.(*ast.StructType); ok {
3355
- sig += " = struct { " + formatFields(st.Fields.List) + " }"
3356
- } else if it, ok := s.Type.(*ast.InterfaceType); ok {
3357
- sig += " = interface { " + formatMethods(it.Methods.List) + " }"
3358
- } else {
3359
- sig += " = " + formatType(s.Type)
3360
- }
3361
- res.Symbols = append(res.Symbols, Sym{Name: typeName, Kind: "type", Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
3362
- case *ast.ValueSpec:
3363
- for _, n := range s.Names {
3364
- valueName := n.Name
3365
- pos := fset.Position(n.Pos())
3366
- kind := "var"
3367
- if d.Tok == token.CONST {
3368
- kind = "const"
3369
- }
3370
- sig := kind + " " + valueName
3371
- if s.Type != nil {
3372
- sig += " " + formatType(s.Type)
3373
- }
3374
- res.Symbols = append(res.Symbols, Sym{Name: valueName, Kind: kind, Line: pos.Line, Col: pos.Column, Signature: sig, Scope: pkgScope})
3375
- }
3376
- }
3377
- }
3378
- }
3379
- }
3380
- ast.Inspect(node, func(n ast.Node) bool {
3381
- switch expr := n.(type) {
3382
- case *ast.CallExpr:
3383
- line := fset.Position(expr.Pos()).Line
3384
- switch fun := expr.Fun.(type) {
3385
- case *ast.Ident:
3386
- res.Refs = append(res.Refs, Ref{ToName: fun.Name, CallType: "call", Line: line})
3387
- case *ast.SelectorExpr:
3388
- res.Refs = append(res.Refs, Ref{ToName: fun.Sel.Name, CallType: "call", Line: line})
3389
- }
3390
- case *ast.ImportSpec:
3391
- if expr.Path != nil {
3392
- if importPath, uerr := strconv.Unquote(expr.Path.Value); uerr == nil {
3393
- line := fset.Position(expr.Pos()).Line
3394
- name := importPath
3395
- if idx := strings.LastIndex(importPath, "/"); idx >= 0 {
3396
- name = importPath[idx+1:]
3397
- }
3398
- res.Refs = append(res.Refs, Ref{ToName: name, CallType: "import", Line: line, Module: importPath})
3399
- }
3400
- }
3401
- }
3402
- return true
3403
- })
3404
- return res
3405
- }
3406
-
3407
- func main() {
3408
- raw, err := io.ReadAll(os.Stdin)
3409
- if err != nil {
3410
- out, _ := json.Marshal(BatchResult{Version: 1, Results: []FileResult{}})
3411
- fmt.Print(string(out))
3412
- return
3413
- }
3414
- var inputs []inputFile
3415
- if err := json.Unmarshal(raw, &inputs); err != nil {
3416
- out, _ := json.Marshal(BatchResult{Version: 1, Results: []FileResult{}})
3417
- fmt.Print(string(out))
3418
- return
3419
- }
3420
- results := make([]FileResult, 0, len(inputs))
3421
- for _, in := range inputs {
3422
- results = append(results, parseOne(in.File, []byte(in.Content)))
3423
- }
3424
- data, err := json.Marshal(BatchResult{Version: 1, Results: results})
3425
- if err != nil {
3426
- fmt.Print("{\\"version\\":1,\\"results\\":[]}")
3427
- return
3428
- }
3429
- fmt.Print(string(data))
3430
- }
3431
-
3432
- func recvTypeName(t ast.Expr) string {
3433
- switch v := t.(type) {
3434
- case *ast.Ident:
3435
- return v.Name
3436
- case *ast.StarExpr:
3437
- return recvTypeName(v.X)
3438
- default:
3439
- return "?"
3440
- }
3441
- }
3442
-
3443
- func formatFuncSig(d *ast.FuncDecl) string {
3444
- scope := ""
3445
- if d.Recv != nil && len(d.Recv.List) > 0 {
3446
- scope = "(" + formatFieldList(d.Recv.List) + ") "
3447
- }
3448
- scope += formatFuncType(d.Type)
3449
- return "func " + scope
3450
- }
3451
-
3452
- func formatFuncType(f *ast.FuncType) string {
3453
- params := formatFieldList(f.Params.List)
3454
- results := ""
3455
- if f.Results != nil {
3456
- results = " -> " + formatFieldList(f.Results.List)
3457
- }
3458
- return params + results
3459
- }
3460
-
3461
- func formatFieldList(fields []*ast.Field) string {
3462
- if len(fields) == 0 {
3463
- return "()"
3464
- }
3465
- names := make([]string, 0, len(fields))
3466
- for _, f := range fields {
3467
- name := ""
3468
- if len(f.Names) > 0 {
3469
- name = f.Names[0].Name
3470
- }
3471
- t := formatType(f.Type)
3472
- if name != "" {
3473
- names = append(names, name+" "+t)
3474
- } else {
3475
- names = append(names, t)
3476
- }
3477
- }
3478
- return "(" + strings.Join(names, ", ") + ")"
3479
- }
3480
-
3481
- func formatFields(fields []*ast.Field) string {
3482
- lines := make([]string, 0)
3483
- for _, f := range fields {
3484
- name := ""
3485
- if len(f.Names) > 0 {
3486
- name = f.Names[0].Name
3487
- }
3488
- t := formatType(f.Type)
3489
- if name != "" {
3490
- lines = append(lines, name+" "+t)
3491
- } else {
3492
- lines = append(lines, t)
3493
- }
3494
- }
3495
- return strings.Join(lines, "; ")
3496
- }
3497
-
3498
- func formatMethods(fields []*ast.Field) string {
3499
- return formatFields(fields)
3500
- }
3501
-
3502
- func formatTypeParams(tp *ast.FieldList) string {
3503
- if tp == nil || len(tp.List) == 0 {
3504
- return ""
3505
- }
3506
- params := make([]string, len(tp.List))
3507
- for i, p := range tp.List {
3508
- if len(p.Names) > 0 {
3509
- params[i] = p.Names[0].Name
3510
- } else {
3511
- params[i] = "T"
3512
- }
3513
- }
3514
- return "[" + strings.Join(params, ", ") + "]"
3515
- }
3516
-
3517
- func formatType(t ast.Expr) string {
3518
- if t == nil {
3519
- return "?"
3520
- }
3521
- switch v := t.(type) {
3522
- case *ast.Ident:
3523
- return v.Name
3524
- case *ast.SelectorExpr:
3525
- return formatType(v.X) + "." + v.Sel.Name
3526
- case *ast.StarExpr:
3527
- return "*" + formatType(v.X)
3528
- case *ast.ArrayType:
3529
- if v.Len == nil {
3530
- return "[]" + formatType(v.Elt)
3531
- }
3532
- return "[...]" + formatType(v.Elt)
3533
- case *ast.MapType:
3534
- return "map[" + formatType(v.Key) + "]" + formatType(v.Value)
3535
- case *ast.InterfaceType:
3536
- return "interface{}"
3537
- case *ast.StructType:
3538
- return "struct{}"
3539
- case *ast.FuncType:
3540
- return formatFuncType(v)
3541
- case *ast.ChanType:
3542
- return "chan " + formatType(v.Value)
3543
- case *ast.BasicLit:
3544
- return v.Value
3545
- case *ast.IndexExpr:
3546
- return formatType(v.X) + "[" + formatType(v.Index) + "]"
3547
- case *ast.IndexListExpr:
3548
- args := make([]string, len(v.Indices))
3549
- for i, idx := range v.Indices {
3550
- args[i] = formatType(idx)
3551
- }
3552
- return formatType(v.X) + "[" + strings.Join(args, ", ") + "]"
3553
- default:
3554
- return "?"
3555
- }
3556
- }
3557
- `;
3558
- var PY_BATCH_SCRIPT = `import ast, json, sys
3559
-
3560
- def get_name(node):
3561
- if isinstance(node, ast.Name):
3562
- return node.id
3563
- elif isinstance(node, ast.Attribute):
3564
- return get_name(node.value) + "." + node.attr
3565
- elif isinstance(node, ast.Subscript):
3566
- return get_name(node.value)
3567
- elif isinstance(node, ast.Call):
3568
- return get_name(node.func)
3569
- elif isinstance(node, ast.Constant):
3570
- return str(node.value)
3571
- return ""
3572
-
3573
- def leaf_name(node):
3574
- if isinstance(node, ast.Attribute):
3575
- return node.attr
3576
- if isinstance(node, ast.Name):
3577
- return node.id
3578
- return get_name(node).split(".")[-1]
3579
-
3580
- def is_private(name):
3581
- return name.startswith("__") and not name.endswith("__")
3582
-
3583
- def parse_one(name, source, module_name):
3584
- result = {"file": name, "symbols": [], "refs": []}
3585
- try:
3586
- tree = ast.parse(source, filename=name)
3587
- except Exception as e:
3588
- result["error"] = str(e)
3589
- return result
3590
- syms = []
3591
- refs = []
3592
- scope_stack = [module_name]
3593
-
3594
- def sym(d):
3595
- return {
3596
- "name": d["name"], "kind": d["kind"], "line": d["line"], "col": d["col"],
3597
- "signature": d["signature"], "scope": d["scope"],
3598
- }
3599
-
3600
- class Visitor(ast.NodeVisitor):
3601
- def visit_ClassDef(self, node):
3602
- bases = [get_name(b) for b in node.bases]
3603
- sig = "class " + node.name
3604
- if bases:
3605
- sig += "(" + ", ".join(bases) + ")"
3606
- sig += ": ..."
3607
- syms.append(sym({
3608
- "name": node.name, "kind": "class", "line": node.lineno,
3609
- "col": node.col_offset, "signature": sig,
3610
- "scope": ".".join(scope_stack) + "." + node.name,
3611
- }))
3612
- scope_stack.append(node.name)
3613
- self.generic_visit(node)
3614
- scope_stack.pop()
3615
-
3616
- def visit_FunctionDef(self, node):
3617
- args = ", ".join(a.arg for a in node.args.args)
3618
- returns = get_name(node.returns) if node.returns is not None else ""
3619
- is_async = isinstance(node, ast.AsyncFunctionDef)
3620
- kind = "function"
3621
- prefix = "def "
3622
- for dec in node.decorator_list:
3623
- d = get_name(dec)
3624
- if d.endswith(".staticmethod"):
3625
- kind = "staticmethod"
3626
- elif d.endswith(".classmethod"):
3627
- kind = "classmethod"
3628
- elif d == "property":
3629
- kind = "property"
3630
- if is_async:
3631
- kind = "async_" + kind
3632
- sig = f"{prefix}{node.name}({args})"
3633
- if returns:
3634
- sig += f" -> {returns}"
3635
- syms.append(sym({
3636
- "name": node.name, "kind": kind, "line": node.lineno,
3637
- "col": node.col_offset, "signature": sig,
3638
- "scope": ".".join(scope_stack) + "." + node.name,
3639
- }))
3640
-
3641
- def visit_AsyncFunctionDef(self, node):
3642
- self.visit_FunctionDef(node)
3643
-
3644
- def visit_Assign(self, node):
3645
- for target in node.targets:
3646
- if isinstance(target, ast.Name):
3647
- tname = target.id
3648
- if is_private(tname):
3649
- continue
3650
- kind = "const" if tname.isupper() else "var"
3651
- col = target.col_offset if hasattr(target, "col_offset") else 0
3652
- syms.append(sym({
3653
- "name": tname, "kind": kind, "line": node.lineno, "col": col,
3654
- "signature": f"{tname} = ...", "scope": ".".join(scope_stack),
3655
- }))
3656
-
3657
- def visit_AnnAssign(self, node):
3658
- if isinstance(node.target, ast.Name):
3659
- tname = node.target.id
3660
- if is_private(tname):
3661
- return
3662
- kind = "const" if tname.isupper() else "var"
3663
- col = node.target.col_offset if hasattr(node.target, "col_offset") else 0
3664
- sig = f"{tname}: {get_name(node.annotation)}"
3665
- if node.value:
3666
- sig += " = ..."
3667
- syms.append(sym({
3668
- "name": tname, "kind": kind, "line": node.lineno, "col": col,
3669
- "signature": sig, "scope": ".".join(scope_stack),
3670
- }))
3671
-
3672
- def visit_Import(self, node):
3673
- # Parity with the single-file parser: imports are symbols too.
3674
- for alias in node.names:
3675
- name = alias.asname or alias.name
3676
- syms.append(sym({
3677
- "name": name, "kind": "import", "line": node.lineno,
3678
- "col": node.col_offset, "signature": f"import {alias.name}",
3679
- "scope": ".".join(scope_stack),
3680
- }))
3681
-
3682
- def visit_ImportFrom(self, node):
3683
- module = node.module or ""
3684
- for alias in node.names:
3685
- name = alias.asname or alias.name
3686
- syms.append(sym({
3687
- "name": name, "kind": "import", "line": node.lineno,
3688
- "col": node.col_offset, "signature": f"from {module} import {alias.name}",
3689
- "scope": ".".join(scope_stack),
3690
- }))
3691
-
3692
- Visitor().visit(tree)
3693
-
3694
- for node in ast.walk(tree):
3695
- if isinstance(node, ast.Call):
3696
- cname = leaf_name(node.func)
3697
- if cname:
3698
- refs.append({"toName": cname, "callType": "call", "line": node.lineno})
3699
- elif isinstance(node, ast.Import):
3700
- for alias in node.names:
3701
- refs.append({
3702
- "toName": alias.name.split(".")[-1], "callType": "import",
3703
- "line": node.lineno, "module": alias.name,
3704
- })
3705
- elif isinstance(node, ast.ImportFrom):
3706
- module = ("." * (node.level or 0)) + (node.module or "")
3707
- for alias in node.names:
3708
- refs.append({
3709
- "toName": alias.name, "callType": "import",
3710
- "line": node.lineno, "module": module,
3711
- })
3712
- elif isinstance(node, ast.ClassDef):
3713
- for base in node.bases:
3714
- bname = leaf_name(base)
3715
- if bname:
3716
- refs.append({"toName": bname, "callType": "inherit", "line": node.lineno})
3717
-
3718
- result["symbols"] = syms
3719
- result["refs"] = refs
3720
- return result
3721
-
3722
- def main():
3723
- try:
3724
- inputs = json.loads(sys.stdin.read())
3725
- except Exception:
3726
- print(json.dumps({"version": 1, "results": []}))
3727
- return
3728
- results = []
3729
- for entry in inputs:
3730
- name = entry.get("file", "")
3731
- module_name = name.rsplit("/", 1)[-1].rsplit("\\\\", 1)[-1][:-3]
3732
- results.append(parse_one(name, entry.get("content", ""), module_name))
3733
- print(json.dumps({"version": 1, "results": results}))
3734
-
3735
- main()
3736
- `;
3737
- var _goBatchScriptPath = null;
3738
- var _pyBatchScriptPath = null;
3739
- async function ensureScriptPath(cached, prefix, fileName, script) {
3740
- if (cached) return { path: cached, wrote: false };
3741
- const dir = await fs2.mkdtemp(path2.join(os.tmpdir(), prefix));
3742
- const scriptPath = path2.join(dir, fileName);
3743
- await fs2.writeFile(scriptPath, script, { encoding: "utf8", flag: "wx" });
3744
- process.once("exit", () => {
3745
- try {
3746
- fsSync.rmSync(dir, { recursive: true, force: true });
3747
- } catch {
3748
- }
3749
- });
3750
- return { path: scriptPath, wrote: true };
3751
- }
3752
- function runToolchainChild(binary, args, stdinPayload, timeoutMs) {
3753
- return new Promise((resolve) => {
3754
- let settled = false;
3755
- let stdout = "";
3756
- let proc;
3757
- try {
3758
- proc = spawn(binary, args, { stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
3759
- } catch {
3760
- resolve(null);
3761
- return;
3762
- }
3763
- const finish = (value) => {
3764
- if (settled) return;
3765
- settled = true;
3766
- clearTimeout(timer);
3767
- resolve(value);
3768
- };
3769
- const timer = setTimeout(() => {
3770
- proc.kill("SIGKILL");
3771
- finish(null);
3772
- }, timeoutMs);
3773
- timer.unref?.();
3774
- proc.on("error", () => finish(null));
3775
- proc.stdout?.on("data", (chunk) => {
3776
- stdout += chunk.toString();
3777
- });
3778
- proc.stderr?.resume();
3779
- proc.stdin?.on("error", () => {
3780
- });
3781
- proc.stdin?.write(stdinPayload);
3782
- proc.stdin?.end();
3783
- proc.on("close", (code) => finish({ code, stdout }));
3784
- });
3785
- }
3786
- async function runGoBatch(files, goBinary) {
3787
- const out = /* @__PURE__ */ new Map();
3788
- if (files.length === 0) return out;
3789
- const { path: scriptPath } = await ensureScriptPath(
3790
- _goBatchScriptPath,
3791
- "ws-go-parse",
3792
- "batch.go",
3793
- GO_BATCH_SCRIPT
3794
- );
3795
- _goBatchScriptPath = scriptPath;
3796
- const payload = JSON.stringify(files.map((f) => ({ file: f.file, content: f.content })));
3797
- const result = await withSpawnGate(
3798
- () => runToolchainChild(
3799
- goBinary ?? resolveWin32Command("go"),
3800
- ["run", scriptPath],
3801
- payload,
3802
- batchTimeoutMs(files.length)
3803
- )
3804
- );
3805
- if (result?.code !== 0 || !result.stdout.trim()) return out;
3806
- for (const entry of parseParserBatchOutput(result.stdout, "go")) {
3807
- if (entry.error !== void 0) continue;
3808
- out.set(entry.file, {
3809
- file: entry.file,
3810
- lang: "go",
3811
- symbols: entry.symbols.map((s) => ({
3812
- id: 0,
3813
- lang: "go",
3814
- kind: s.kind,
3815
- name: s.name,
3816
- file: entry.file,
3817
- line: s.line,
3818
- col: s.col,
3819
- signature: s.signature ?? "",
3820
- docComment: "",
3821
- scope: s.scope ?? "",
3822
- text: `${s.name} ${s.signature ?? ""}`.trim()
3823
- })),
3824
- refs: entry.refs,
3825
- mtimeMs: Date.now()
3826
- });
3827
- }
3828
- return out;
3829
- }
3830
- async function runPyBatch(files, pythonBinary) {
3831
- const out = /* @__PURE__ */ new Map();
3832
- if (files.length === 0) return out;
3833
- const { path: scriptPath } = await ensureScriptPath(
3834
- _pyBatchScriptPath,
3835
- "ws-py-parse",
3836
- "batch.py",
3837
- PY_BATCH_SCRIPT
3838
- );
3839
- _pyBatchScriptPath = scriptPath;
3840
- const payload = JSON.stringify(files.map((f) => ({ file: f.file, content: f.content })));
3841
- const result = await withSpawnGate(
3842
- () => runToolchainChild(pythonBinary, [scriptPath], payload, batchTimeoutMs(files.length))
3843
- );
3844
- if (result?.code !== 0 || !result.stdout.trim()) return out;
3845
- for (const entry of parseParserBatchOutput(result.stdout, "py")) {
3846
- if (entry.error !== void 0) continue;
3847
- out.set(entry.file, {
3848
- file: entry.file,
3849
- lang: "py",
3850
- symbols: entry.symbols.map((s) => ({
3851
- id: 0,
3852
- lang: "py",
3853
- kind: s.kind,
3854
- name: s.name,
3855
- file: entry.file,
3856
- line: s.line,
3857
- col: s.col,
3858
- signature: s.signature ?? "",
3859
- docComment: "",
3860
- scope: s.scope ?? "",
3861
- text: `${s.name} ${s.signature ?? ""}`.trim()
3862
- })),
3863
- refs: entry.refs,
3864
- mtimeMs: Date.now()
3865
- });
3866
- }
3867
- return out;
3868
- }
3869
-
3870
- // src/codebase-index/parser-dispatch.ts
3871
- init_py_parser();
3872
- async function parseFileContent(file, content, lang) {
3873
- const parsed = await dispatch(file, content, lang);
3874
- return withRelations(parsed, content, lang);
3875
- }
3876
- async function parseFilesContent(files) {
3877
- if (files.length === 0) return [];
3878
- const slots = files.map(() => ({ result: null }));
3879
- const batchingEnabled = process.env["WRONGSTACK_TOOLCHAIN_BATCH"] !== "0";
3880
- if (batchingEnabled) {
3881
- const goFiles = [];
3882
- const pyFiles = [];
3883
- files.forEach((f, index) => {
3884
- if (f.lang === "go") goFiles.push({ ...f, index });
3885
- else if (f.lang === "py") pyFiles.push({ ...f, index });
3886
- });
3887
- if (goFiles.length > 0) {
3888
- await applyBatchResults(slots, goFiles, (chunks) => runGoBatch(chunks), "go");
3889
- }
3890
- if (pyFiles.length > 0) {
3891
- const pyBinary = await resolvePythonBinary();
3892
- if (pyBinary) {
3893
- await applyBatchResults(slots, pyFiles, (chunks) => runPyBatch(chunks, pyBinary), "py");
3894
- }
3895
- }
3896
- }
3897
- const jobs = [];
3898
- for (let i = 0; i < files.length; i++) {
3899
- if (slots[i].result !== null) continue;
3900
- const { file, content, lang } = files[i];
3901
- const slot = slots[i];
3902
- jobs.push(
3903
- (async () => {
3904
- try {
3905
- slot.result = await parseFileContent(file, content, lang);
3906
- } catch (err) {
3907
- slot.error = err instanceof Error ? err.message : String(err);
3908
- }
3909
- })()
3910
- );
3911
- }
3912
- await Promise.all(jobs);
3913
- return slots;
3914
- }
3915
- async function applyBatchResults(slots, batchFiles, runBatch, lang) {
3916
- for (const chunk of chunkBatchFiles(batchFiles)) {
3917
- let byFile = null;
3918
- try {
3919
- byFile = await runBatch(chunk);
3920
- } catch {
3921
- byFile = null;
3922
- }
3923
- if (!byFile) continue;
3924
- for (const item of chunk) {
3925
- const parsed = byFile.get(item.file);
3926
- if (!parsed) continue;
3927
- slots[item.index] = { result: withRelations(parsed, item.content, lang) };
3928
- }
3929
- }
3930
- }
3931
- async function dispatch(file, content, lang) {
3932
- switch (lang) {
3933
- case "ts":
3934
- case "tsx":
3935
- case "js":
3936
- case "jsx": {
3937
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_ts_parser(), ts_parser_exports));
3938
- return parseSymbols9({ file, content, lang });
3939
- }
3940
- case "go": {
3941
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_go_parser(), go_parser_exports));
3942
- return parseSymbols9({ file, content, lang: "go" });
3943
- }
3944
- case "py": {
3945
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_py_parser(), py_parser_exports));
3946
- return parseSymbols9({ file, content, lang: "py" });
3947
- }
3948
- case "rs": {
3949
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_rs_parser(), rs_parser_exports));
3950
- return parseSymbols9({ file, content, lang: "rs" });
3951
- }
3952
- case "json": {
3953
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_json_parser(), json_parser_exports));
3954
- return parseSymbols9({ file, content, lang: "json" });
3955
- }
3956
- case "yaml": {
3957
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_yaml_parser(), yaml_parser_exports));
3958
- return parseSymbols9({ file, content, lang: "yaml" });
3959
- }
3960
- // Phase 1: ten languages now route through the Tree-Sitter WASM
3961
- // universal parser (`tree-sitter-parser.ts`). The dispatch falls back to
3962
- // the regex extractor in `generic-parser.ts` whenever WASM loading fails
3963
- // or the parser returns zero symbols — preserving the indexable-file
3964
- // contract that "missing a parser must never mean skipping the file".
3965
- case "c":
3966
- case "cpp":
3967
- case "java":
3968
- case "csharp":
3969
- case "php":
3970
- case "ruby":
3971
- case "swift":
3972
- case "kotlin":
3973
- case "shell":
3974
- case "elixir": {
3975
- try {
3976
- const { parseSymbols: parseSymbols10 } = await Promise.resolve().then(() => (init_tree_sitter_parser(), tree_sitter_parser_exports));
3977
- const parsed = await parseSymbols10({ file, content, lang });
3978
- if (parsed.symbols.length > 0) return parsed;
3979
- } catch {
3980
- }
3981
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_generic_parser(), generic_parser_exports));
3982
- return parseSymbols9({ file, content, lang });
3983
- }
3984
- default: {
3985
- const { parseSymbols: parseSymbols9 } = await Promise.resolve().then(() => (init_generic_parser(), generic_parser_exports));
3986
- return parseSymbols9({ file, content, lang });
3987
- }
3988
- }
3989
- }
3990
- function withRelations(parsed, content, lang) {
3991
- let refs = parsed.refs ?? [];
3992
- if (refs.length === 0 && hasImportPatterns(lang)) {
3993
- refs = extractImports({ content, lang });
3994
- }
3995
- return { ...parsed, refs: refs.map((ref) => ref.lang ? ref : { ...ref, lang }) };
3996
- }
3997
-
3998
- // src/codebase-index/parser-worker-script.ts
3999
12
  if (!parentPort) {
4000
13
  throw new Error("parser-worker-script must be started as a worker thread");
4001
14
  }