pi-lens 3.6.2 → 3.6.4

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 (207) hide show
  1. package/CHANGELOG.md +10 -2
  2. package/package.json +4 -4
  3. package/tsconfig.json +1 -1
  4. package/clients/__tests__/file-time.test.js +0 -216
  5. package/clients/__tests__/file-time.test.ts +0 -276
  6. package/clients/__tests__/format-service.test.js +0 -245
  7. package/clients/__tests__/format-service.test.ts +0 -339
  8. package/clients/__tests__/formatters.test.js +0 -271
  9. package/clients/__tests__/formatters.test.ts +0 -401
  10. package/clients/agent-behavior-client.js +0 -110
  11. package/clients/agent-behavior-client.test.js +0 -94
  12. package/clients/agent-behavior-client.test.ts +0 -116
  13. package/clients/amain-types.js +0 -164
  14. package/clients/architect-client.js +0 -291
  15. package/clients/ast-grep-client.js +0 -253
  16. package/clients/ast-grep-parser.js +0 -84
  17. package/clients/ast-grep-rule-manager.js +0 -89
  18. package/clients/ast-grep-types.js +0 -9
  19. package/clients/auto-loop.js +0 -131
  20. package/clients/biome-client.js +0 -420
  21. package/clients/biome-client.test.js +0 -144
  22. package/clients/biome-client.test.ts +0 -163
  23. package/clients/cache/rule-cache.js +0 -72
  24. package/clients/cache-manager.js +0 -245
  25. package/clients/cache-manager.test.js +0 -197
  26. package/clients/cache-manager.test.ts +0 -299
  27. package/clients/complexity-client.js +0 -675
  28. package/clients/complexity-client.test.js +0 -234
  29. package/clients/complexity-client.test.ts +0 -255
  30. package/clients/config-validator.js +0 -465
  31. package/clients/dependency-checker.js +0 -325
  32. package/clients/dependency-checker.test.js +0 -60
  33. package/clients/dependency-checker.test.ts +0 -71
  34. package/clients/dispatch/__tests__/autofix-integration.test.js +0 -245
  35. package/clients/dispatch/__tests__/autofix-integration.test.ts +0 -300
  36. package/clients/dispatch/__tests__/runner-registration.test.js +0 -234
  37. package/clients/dispatch/__tests__/runner-registration.test.ts +0 -286
  38. package/clients/dispatch/debug.log +0 -1
  39. package/clients/dispatch/dispatcher.edge.test.js +0 -82
  40. package/clients/dispatch/dispatcher.edge.test.ts +0 -100
  41. package/clients/dispatch/dispatcher.format.test.js +0 -46
  42. package/clients/dispatch/dispatcher.format.test.ts +0 -58
  43. package/clients/dispatch/dispatcher.inline.test.js +0 -74
  44. package/clients/dispatch/dispatcher.inline.test.ts +0 -93
  45. package/clients/dispatch/dispatcher.js +0 -381
  46. package/clients/dispatch/dispatcher.test.js +0 -116
  47. package/clients/dispatch/dispatcher.test.ts +0 -149
  48. package/clients/dispatch/integration.js +0 -108
  49. package/clients/dispatch/plan.js +0 -183
  50. package/clients/dispatch/runners/architect.js +0 -83
  51. package/clients/dispatch/runners/architect.test.js +0 -138
  52. package/clients/dispatch/runners/architect.test.ts +0 -162
  53. package/clients/dispatch/runners/ast-grep-napi.js +0 -405
  54. package/clients/dispatch/runners/ast-grep-napi.test.js +0 -107
  55. package/clients/dispatch/runners/ast-grep-napi.test.ts +0 -129
  56. package/clients/dispatch/runners/ast-grep.js +0 -157
  57. package/clients/dispatch/runners/biome.js +0 -55
  58. package/clients/dispatch/runners/config-validation.js +0 -67
  59. package/clients/dispatch/runners/go-vet.js +0 -48
  60. package/clients/dispatch/runners/index.js +0 -47
  61. package/clients/dispatch/runners/lsp.js +0 -102
  62. package/clients/dispatch/runners/oxlint.js +0 -67
  63. package/clients/dispatch/runners/oxlint.test.js +0 -230
  64. package/clients/dispatch/runners/oxlint.test.ts +0 -303
  65. package/clients/dispatch/runners/pyright.js +0 -100
  66. package/clients/dispatch/runners/pyright.test.js +0 -98
  67. package/clients/dispatch/runners/pyright.test.ts +0 -121
  68. package/clients/dispatch/runners/python-slop.js +0 -97
  69. package/clients/dispatch/runners/python-slop.test.js +0 -203
  70. package/clients/dispatch/runners/python-slop.test.ts +0 -298
  71. package/clients/dispatch/runners/ruff.js +0 -48
  72. package/clients/dispatch/runners/rust-clippy.js +0 -102
  73. package/clients/dispatch/runners/scan_codebase.test.js +0 -89
  74. package/clients/dispatch/runners/scan_codebase.test.ts +0 -105
  75. package/clients/dispatch/runners/shellcheck.js +0 -147
  76. package/clients/dispatch/runners/shellcheck.test.js +0 -98
  77. package/clients/dispatch/runners/shellcheck.test.ts +0 -129
  78. package/clients/dispatch/runners/similarity.js +0 -230
  79. package/clients/dispatch/runners/spellcheck.js +0 -106
  80. package/clients/dispatch/runners/spellcheck.test.js +0 -158
  81. package/clients/dispatch/runners/spellcheck.test.ts +0 -214
  82. package/clients/dispatch/runners/tree-sitter.js +0 -246
  83. package/clients/dispatch/runners/ts-lsp.js +0 -125
  84. package/clients/dispatch/runners/ts-slop.js +0 -113
  85. package/clients/dispatch/runners/type-safety.js +0 -142
  86. package/clients/dispatch/runners/utils/diagnostic-parsers.js +0 -134
  87. package/clients/dispatch/runners/utils/runner-helpers.js +0 -115
  88. package/clients/dispatch/runners/utils.js +0 -51
  89. package/clients/dispatch/runners/yaml-rule-parser.js +0 -360
  90. package/clients/dispatch/types.js +0 -16
  91. package/clients/dispatch/utils/format-utils.js +0 -44
  92. package/clients/dogfood.test.js +0 -201
  93. package/clients/dogfood.test.ts +0 -269
  94. package/clients/file-kinds.js +0 -177
  95. package/clients/file-kinds.test.js +0 -169
  96. package/clients/file-kinds.test.ts +0 -210
  97. package/clients/file-time.js +0 -152
  98. package/clients/file-utils.js +0 -40
  99. package/clients/fix-scanners.js +0 -204
  100. package/clients/format-service.js +0 -184
  101. package/clients/formatters.js +0 -488
  102. package/clients/go-client.js +0 -203
  103. package/clients/go-client.test.js +0 -127
  104. package/clients/go-client.test.ts +0 -143
  105. package/clients/installer/index.js +0 -403
  106. package/clients/interviewer-templates.js +0 -75
  107. package/clients/interviewer.js +0 -173
  108. package/clients/jscpd-client.js +0 -196
  109. package/clients/jscpd-client.test.js +0 -127
  110. package/clients/jscpd-client.test.ts +0 -145
  111. package/clients/knip-client.js +0 -239
  112. package/clients/knip-client.test.js +0 -112
  113. package/clients/knip-client.test.ts +0 -128
  114. package/clients/latency-logger.js +0 -40
  115. package/clients/lsp/__tests__/client.test.js +0 -310
  116. package/clients/lsp/__tests__/client.test.ts +0 -412
  117. package/clients/lsp/__tests__/config.test.js +0 -167
  118. package/clients/lsp/__tests__/config.test.ts +0 -217
  119. package/clients/lsp/__tests__/error-recovery.test.js +0 -213
  120. package/clients/lsp/__tests__/error-recovery.test.ts +0 -279
  121. package/clients/lsp/__tests__/integration.test.js +0 -127
  122. package/clients/lsp/__tests__/integration.test.ts +0 -160
  123. package/clients/lsp/__tests__/launch.test.js +0 -313
  124. package/clients/lsp/__tests__/launch.test.ts +0 -394
  125. package/clients/lsp/__tests__/server.test.js +0 -259
  126. package/clients/lsp/__tests__/server.test.ts +0 -332
  127. package/clients/lsp/__tests__/service.test.js +0 -438
  128. package/clients/lsp/__tests__/service.test.ts +0 -530
  129. package/clients/lsp/client.js +0 -350
  130. package/clients/lsp/config.js +0 -112
  131. package/clients/lsp/index.js +0 -318
  132. package/clients/lsp/installer/index.js +0 -391
  133. package/clients/lsp/interactive-install.js +0 -221
  134. package/clients/lsp/language.js +0 -170
  135. package/clients/lsp/launch.js +0 -329
  136. package/clients/lsp/lsp/launch.js +0 -116
  137. package/clients/lsp/lsp/server.js +0 -532
  138. package/clients/lsp/lsp-index.js +0 -10
  139. package/clients/lsp/path-utils.js +0 -5
  140. package/clients/lsp/server.js +0 -725
  141. package/clients/lsp/test-py-spawn/requirements.txt +0 -1
  142. package/clients/lsp/test-py-spawn/test.py +0 -3
  143. package/clients/lsp/test-py-svc/requirements.txt +0 -1
  144. package/clients/lsp/test-py-svc/test.py +0 -3
  145. package/clients/lsp/test-python-project/requirements.txt +0 -1
  146. package/clients/lsp/test-python-project/test.py +0 -5
  147. package/clients/metrics-client.js +0 -107
  148. package/clients/metrics-client.test.js +0 -128
  149. package/clients/metrics-client.test.ts +0 -163
  150. package/clients/metrics-history.js +0 -367
  151. package/clients/path-utils.js +0 -142
  152. package/clients/pipeline.js +0 -272
  153. package/clients/production-readiness.js +0 -522
  154. package/clients/project-index.js +0 -255
  155. package/clients/project-metadata.js +0 -531
  156. package/clients/ruff-client.js +0 -325
  157. package/clients/ruff-client.test.js +0 -132
  158. package/clients/ruff-client.test.ts +0 -153
  159. package/clients/rules-scanner.js +0 -97
  160. package/clients/runner-tracker.js +0 -152
  161. package/clients/rust-client.js +0 -205
  162. package/clients/rust-client.test.js +0 -108
  163. package/clients/rust-client.test.ts +0 -130
  164. package/clients/safe-spawn-async.js +0 -163
  165. package/clients/safe-spawn.js +0 -241
  166. package/clients/sanitize.js +0 -291
  167. package/clients/sanitize.test.js +0 -177
  168. package/clients/sanitize.test.ts +0 -223
  169. package/clients/scan-architectural-debt.js +0 -167
  170. package/clients/scan-utils.js +0 -83
  171. package/clients/secrets-scanner.js +0 -119
  172. package/clients/secrets-scanner.test.js +0 -100
  173. package/clients/secrets-scanner.test.ts +0 -113
  174. package/clients/sg-runner.js +0 -292
  175. package/clients/state-matrix.js +0 -160
  176. package/clients/subprocess-client.js +0 -65
  177. package/clients/symbol-types.js +0 -5
  178. package/clients/test-runner-client.js +0 -523
  179. package/clients/test-runner-client.test.js +0 -192
  180. package/clients/test-runner-client.test.ts +0 -253
  181. package/clients/test-utils.js +0 -27
  182. package/clients/test-utils.ts +0 -36
  183. package/clients/todo-scanner.js +0 -200
  184. package/clients/todo-scanner.test.js +0 -301
  185. package/clients/todo-scanner.test.ts +0 -352
  186. package/clients/tool-availability.js +0 -207
  187. package/clients/tree-sitter-client.js +0 -601
  188. package/clients/tree-sitter-query-loader.js +0 -355
  189. package/clients/tree-sitter-symbol-extractor.js +0 -289
  190. package/clients/ts-service.js +0 -129
  191. package/clients/type-coverage-client.js +0 -127
  192. package/clients/type-coverage-client.test.js +0 -105
  193. package/clients/type-coverage-client.test.ts +0 -125
  194. package/clients/type-safety-client.js +0 -138
  195. package/clients/types.js +0 -11
  196. package/clients/typescript-client.codefix.test.js +0 -157
  197. package/clients/typescript-client.codefix.test.ts +0 -186
  198. package/clients/typescript-client.js +0 -509
  199. package/clients/typescript-client.test.js +0 -105
  200. package/clients/typescript-client.test.ts +0 -126
  201. package/commands/booboo.js +0 -1007
  202. package/commands/fix-from-booboo.js +0 -398
  203. package/commands/fix-simplified.js +0 -618
  204. package/commands/rate.js +0 -281
  205. package/commands/rate.test.js +0 -119
  206. package/commands/rate.test.ts +0 -131
  207. package/commands/refactor.js +0 -130
@@ -1,355 +0,0 @@
1
- /**
2
- * Tree-sitter Query Loader
3
- *
4
- * Loads tree-sitter queries from YAML files in rules/tree-sitter-queries/
5
- * and provides them to the TreeSitterClient.
6
- */
7
- import * as fs from "node:fs";
8
- import * as path from "node:path";
9
- import { fileURLToPath } from "node:url";
10
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
- export class TreeSitterQueryLoader {
12
- constructor(verbose = false) {
13
- this.queries = new Map();
14
- this.loaded = false;
15
- this.verbose = verbose;
16
- }
17
- /** Debug logging helper */
18
- dbg(msg) {
19
- if (this.verbose) {
20
- console.error(`[query-loader] ${msg}`);
21
- }
22
- }
23
- /**
24
- * Load all queries from the rules/tree-sitter-queries directory
25
- */
26
- async loadQueries() {
27
- if (this.loaded)
28
- return this.queries;
29
- const queriesDir = path.join(process.cwd(), "rules", "tree-sitter-queries");
30
- if (!fs.existsSync(queriesDir)) {
31
- this.dbg(`Queries directory not found: ${queriesDir}`);
32
- return this.queries;
33
- }
34
- // Load queries from each language subdirectory
35
- const languageDirs = fs
36
- .readdirSync(queriesDir, { withFileTypes: true })
37
- .filter((d) => d.isDirectory())
38
- .map((d) => d.name);
39
- for (const lang of languageDirs) {
40
- const langDir = path.join(queriesDir, lang);
41
- const queryFiles = fs
42
- .readdirSync(langDir)
43
- .filter((f) => f.endsWith(".yml"));
44
- const langQueries = [];
45
- for (const file of queryFiles) {
46
- const filePath = path.join(langDir, file);
47
- const query = this.parseQueryFile(filePath, lang);
48
- if (query) {
49
- langQueries.push(query);
50
- }
51
- }
52
- if (langQueries.length > 0) {
53
- this.queries.set(lang, langQueries);
54
- this.dbg(`Loaded ${langQueries.length} queries for ${lang}`);
55
- }
56
- }
57
- this.loaded = true;
58
- return this.queries;
59
- }
60
- /**
61
- * Parse a single YAML query file
62
- */
63
- parseQueryFile(filePath, language) {
64
- try {
65
- const content = fs.readFileSync(filePath, "utf-8");
66
- // Simple YAML parsing (extract key: value pairs)
67
- const parsed = this.parseYaml(content);
68
- if (!parsed.id || !parsed.query) {
69
- this.dbg(`Invalid query file: ${filePath}`);
70
- return null;
71
- }
72
- return {
73
- id: String(parsed.id),
74
- name: String(parsed.name || parsed.id),
75
- severity: this.parseSeverity(parsed.severity),
76
- category: String(parsed.category || "general"),
77
- language: String(parsed.language || language),
78
- message: String(parsed.message || `Pattern: ${parsed.id}`),
79
- description: parsed.description
80
- ? String(parsed.description)
81
- : undefined,
82
- query: this.extractMultilineValue(content, "query") || String(parsed.query),
83
- metavars: Array.isArray(parsed.metavars)
84
- ? parsed.metavars.map(String)
85
- : this.extractMetavars(String(parsed.query)),
86
- post_filter: parsed.post_filter
87
- ? String(parsed.post_filter)
88
- : undefined,
89
- // biome-ignore lint/suspicious/noExplicitAny: Post filter params
90
- post_filter_params: parsed.post_filter_params,
91
- tags: Array.isArray(parsed.tags) ? parsed.tags.map(String) : undefined,
92
- has_fix: parsed.has_fix === true || parsed.has_fix === "true",
93
- fix_action: parsed.fix_action ? String(parsed.fix_action) : undefined,
94
- filePath,
95
- };
96
- }
97
- catch (err) {
98
- this.dbg(`Failed to parse ${filePath}: ${err}`);
99
- return null;
100
- }
101
- }
102
- /**
103
- * Simple YAML parser for our query files
104
- */
105
- parseYaml(content) {
106
- const result = {};
107
- const lines = content.split("\n");
108
- for (let i = 0; i < lines.length; i++) {
109
- const line = lines[i];
110
- const match = line.match(/^([a-z_]+):\s*(.*)$/);
111
- if (match) {
112
- const key = match[1];
113
- let value = match[2].trim();
114
- // Handle arrays inline: metavars: [A, B, C]
115
- if (value.startsWith("[") && value.endsWith("]")) {
116
- value = value
117
- .slice(1, -1)
118
- .split(",")
119
- .map((s) => s.trim().replace(/^["']|["']$/g, ""));
120
- }
121
- // Handle multi-line arrays: metavars:\n - A\n - B
122
- else if (value === "") {
123
- // Check if next lines are array items ( - item)
124
- const arrayItems = [];
125
- const baseIndent = line.match(/^(\s*)/)?.[0].length || 0;
126
- for (let j = i + 1; j < lines.length; j++) {
127
- const nextLine = lines[j];
128
- const nextIndent = nextLine.match(/^(\s*)/)?.[0].length || 0;
129
- // Stop if we hit a line with same or less indent (new key)
130
- if (nextIndent <= baseIndent && nextLine.match(/^[a-z_]+:/)) {
131
- break;
132
- }
133
- // Check if it's an array item
134
- const itemMatch = nextLine.match(/^\s+-\s*(.+)$/);
135
- if (itemMatch) {
136
- // Strip inline comments and trim
137
- const item = itemMatch[1].trim().replace(/\s*#.*$/, "");
138
- if (item)
139
- arrayItems.push(item);
140
- }
141
- }
142
- if (arrayItems.length > 0) {
143
- value = arrayItems;
144
- }
145
- }
146
- // Handle booleans
147
- else if (value === "true")
148
- value = true;
149
- else if (value === "false")
150
- value = false;
151
- // Strip quotes from strings
152
- else if (value.startsWith('"') && value.endsWith('"')) {
153
- value = value.slice(1, -1);
154
- }
155
- result[key] = value;
156
- }
157
- }
158
- return result;
159
- }
160
- /**
161
- * Extract a multiline value (like query) from YAML
162
- */
163
- extractMultilineValue(content, key) {
164
- const lines = content.split("\n");
165
- let startLine = -1;
166
- let startIndent = 0;
167
- const keyPrefix = `${key}:`;
168
- // Find the key line
169
- for (let i = 0; i < lines.length; i++) {
170
- const trimmed = lines[i].trimStart();
171
- if (trimmed.startsWith(keyPrefix)) {
172
- startLine = i;
173
- startIndent = lines[i].length - trimmed.length;
174
- const afterKey = trimmed.slice(keyPrefix.length).trim();
175
- // If there's content on the same line (not just |), return it
176
- if (afterKey && afterKey !== "|")
177
- return afterKey;
178
- break;
179
- }
180
- }
181
- if (startLine === -1)
182
- return null;
183
- // Collect all lines until we hit a new key with same or less indent
184
- const valueLines = [];
185
- for (let i = startLine + 1; i < lines.length; i++) {
186
- const line = lines[i];
187
- // Track empty lines
188
- if (!line.trim()) {
189
- valueLines.push("");
190
- continue;
191
- }
192
- // Check indent
193
- const indentMatch = line.match(/^(\s*)/);
194
- const indent = indentMatch ? indentMatch[1].length : 0;
195
- const trimmed = line.trim();
196
- // Stop at new key with same or less indent (but not at comments)
197
- if (indent <= startIndent &&
198
- trimmed.match(/^[a-z_]+:/) &&
199
- !trimmed.startsWith("#")) {
200
- break;
201
- }
202
- // Skip comment lines (they're not part of the value)
203
- if (trimmed.startsWith("#"))
204
- continue;
205
- // This is part of the multiline value
206
- valueLines.push(line.slice(startIndent));
207
- }
208
- // Clean up - remove trailing empty lines
209
- while (valueLines.length > 0 && !valueLines[valueLines.length - 1].trim()) {
210
- valueLines.pop();
211
- }
212
- return valueLines.length > 0 ? valueLines.join("\n") : null;
213
- }
214
- /**
215
- * Parse severity string to valid type
216
- */
217
- parseSeverity(value) {
218
- if (value === "error")
219
- return "error";
220
- if (value === "warning")
221
- return "warning";
222
- if (value === "info")
223
- return "info";
224
- return "warning"; // default
225
- }
226
- /**
227
- * Extract @VAR patterns from query string
228
- */
229
- extractMetavars(query) {
230
- const matches = query.match(/@([A-Z_][A-Z0-9_]*)/g);
231
- if (!matches)
232
- return [];
233
- return [...new Set(matches.map((m) => m.slice(1)))];
234
- }
235
- /**
236
- * Get queries for a specific language
237
- */
238
- getQueriesForLanguage(language) {
239
- return this.queries.get(language) || [];
240
- }
241
- /**
242
- * Get a specific query by ID
243
- */
244
- getQueryById(id) {
245
- for (const langQueries of this.queries.values()) {
246
- const query = langQueries.find((q) => q.id === id);
247
- if (query)
248
- return query;
249
- }
250
- return undefined;
251
- }
252
- /**
253
- * Find matching query for a pattern string
254
- */
255
- findMatchingQuery(pattern, language) {
256
- const langQueries = this.getQueriesForLanguage(language);
257
- // Check for pattern keywords
258
- for (const query of langQueries) {
259
- // Match by ID
260
- if (pattern.includes(query.id))
261
- return query;
262
- // Match by keywords in pattern
263
- switch (query.id) {
264
- case "empty-catch":
265
- if (pattern.includes("empty-catch") || pattern.includes("catch {}"))
266
- return query;
267
- break;
268
- case "debugger-statement":
269
- if (pattern.includes("debugger"))
270
- return query;
271
- break;
272
- case "await-in-loop":
273
- if (pattern.includes("await-in-loop") || pattern.includes("await"))
274
- return query;
275
- break;
276
- case "hardcoded-secrets":
277
- if (pattern.includes("hardcoded") ||
278
- pattern.includes("api_key") ||
279
- pattern.includes("password"))
280
- return query;
281
- break;
282
- case "dangerously-set-inner-html":
283
- if (pattern.includes("dangerously") || pattern.includes("innerHTML"))
284
- return query;
285
- break;
286
- case "nested-ternary":
287
- if (pattern.includes("ternary") || pattern.includes("? :"))
288
- return query;
289
- break;
290
- case "no-eval":
291
- if (pattern.includes("eval") && !pattern.includes("console"))
292
- return query;
293
- break;
294
- case "deep-promise-chain":
295
- if (pattern.includes(".then") && pattern.includes(".catch"))
296
- return query;
297
- break;
298
- case "console-statement":
299
- if (pattern.includes("console"))
300
- return query;
301
- break;
302
- case "long-parameter-list":
303
- if (pattern.includes("PARAMS"))
304
- return query;
305
- break;
306
- // Python queries
307
- case "bare-except":
308
- if (pattern.includes("bare-except") || pattern.includes("except:"))
309
- return query;
310
- break;
311
- case "mutable-default-arg":
312
- if (pattern.includes("mutable") || pattern.includes("default"))
313
- return query;
314
- break;
315
- case "wildcard-import":
316
- if (pattern.includes("wildcard") || pattern.includes("import *"))
317
- return query;
318
- break;
319
- case "eval-exec":
320
- if (pattern.includes("eval") || pattern.includes("exec"))
321
- return query;
322
- break;
323
- case "is-vs-equals":
324
- if (pattern.includes("is") || pattern.includes("equals"))
325
- return query;
326
- break;
327
- case "unreachable-except":
328
- if (pattern.includes("unreachable") || pattern.includes("except"))
329
- return query;
330
- break;
331
- }
332
- }
333
- return undefined;
334
- }
335
- /**
336
- * Get all loaded queries
337
- */
338
- getAllQueries() {
339
- const all = [];
340
- for (const queries of this.queries.values()) {
341
- all.push(...queries);
342
- }
343
- return all;
344
- }
345
- /**
346
- * Reload queries from disk
347
- */
348
- async reload() {
349
- this.queries.clear();
350
- this.loaded = false;
351
- await this.loadQueries();
352
- }
353
- }
354
- // Singleton instance
355
- export const queryLoader = new TreeSitterQueryLoader();
@@ -1,289 +0,0 @@
1
- /**
2
- * Symbol extraction via tree-sitter queries
3
- * Extracts definitions and references from source files
4
- */
5
- import * as path from "node:path";
6
- // Tree-sitter query patterns for symbol extraction
7
- const SYMBOL_QUERIES = {
8
- typescript: {
9
- defs: `
10
- ;; Function declarations: function foo(params) { }
11
- (function_declaration
12
- name: (identifier) @funcName
13
- parameters: (formal_parameters) @funcParams
14
- body: (statement_block) @funcBody) @funcDef
15
-
16
- ;; Arrow functions: const foo = (params) => { }
17
- (variable_declarator
18
- name: (identifier) @arrowName
19
- value: (arrow_function
20
- parameters: (formal_parameters) @arrowParams
21
- body: (_) @arrowBody)) @arrowDef
22
-
23
- ;; Class declarations: class Foo { }
24
- (class_declaration
25
- name: (type_identifier) @className) @classDef
26
-
27
- ;; Method definitions: class Foo { bar() { } }
28
- (method_definition
29
- name: (property_identifier) @methodName
30
- parameters: (formal_parameters) @methodParams) @methodDef
31
-
32
- ;; Interface declarations: interface Foo { }
33
- (interface_declaration
34
- name: (type_identifier) @interfaceName) @interfaceDef
35
-
36
- ;; Type alias: type Foo = ...
37
- (type_alias_declaration
38
- name: (type_identifier) @typeName) @typeDef
39
- `,
40
- refs: `
41
- ;; Function/method calls: foo() or obj.bar()
42
- (call_expression
43
- function: (identifier) @callIdent) @callRef
44
-
45
- (call_expression
46
- function: (member_expression
47
- object: (_)
48
- property: (property_identifier) @callMethod)) @callMethodRef
49
-
50
- ;; New expressions: new Foo()
51
- (new_expression
52
- constructor: (identifier) @newIdent) @newRef
53
-
54
- ;; Type references: type T = Foo
55
- (type_identifier) @typeIdent
56
- `,
57
- },
58
- python: {
59
- defs: `
60
- ;; Function definitions: def foo(params):
61
- (function_definition
62
- name: (identifier) @funcName
63
- parameters: (parameters) @funcParams) @funcDef
64
-
65
- ;; Class definitions: class Foo:
66
- (class_definition
67
- name: (identifier) @className) @classDef
68
-
69
- ;; Method definitions (within class)
70
- (class_definition
71
- body: (block
72
- (function_definition
73
- name: (identifier) @methodName
74
- parameters: (parameters) @methodParams) @methodDef))
75
- `,
76
- refs: `
77
- ;; Function calls: foo() or obj.bar()
78
- (call
79
- function: (identifier) @callIdent) @callRef
80
-
81
- (call
82
- function: (attribute
83
- object: (_)
84
- attribute: (identifier) @callMethod)) @callMethodRef
85
- `,
86
- },
87
- rust: {
88
- defs: `
89
- ;; Function definitions: fn foo(params) { }
90
- (function_item
91
- name: (identifier) @funcName
92
- parameters: (parameters) @funcParams) @funcDef
93
-
94
- ;; Struct definitions: struct Foo { }
95
- (struct_item
96
- name: (type_identifier) @structName) @structDef
97
-
98
- ;; Impl blocks: impl Foo { fn bar() { } }
99
- (impl_item
100
- type: (type_identifier) @implType
101
- body: (declaration_list
102
- (function_item
103
- name: (identifier) @implMethodName) @implMethodDef))
104
- `,
105
- refs: `
106
- ;; Function calls: foo() or obj.bar()
107
- (call_expression
108
- function: (identifier) @callIdent) @callRef
109
-
110
- (call_expression
111
- function: (field_expression
112
- value: (_)
113
- field: (field_identifier) @callField)) @callFieldRef
114
- `,
115
- },
116
- };
117
- export class TreeSitterSymbolExtractor {
118
- constructor(languageId, client) {
119
- this.languageId = languageId;
120
- this.client = client;
121
- }
122
- async init() {
123
- try {
124
- // Get language from client
125
- const language = this.client.getLanguage(this.languageId);
126
- if (!language)
127
- return false;
128
- const { Query } = await import("web-tree-sitter");
129
- const queries = SYMBOL_QUERIES[this.languageId];
130
- if (!queries)
131
- return false;
132
- // biome-ignore lint/suspicious/noExplicitAny: Language type
133
- this.defQuery = new Query(language, queries.defs);
134
- // biome-ignore lint/suspicious/noExplicitAny: Language type
135
- this.refQuery = new Query(language, queries.refs);
136
- return true;
137
- }
138
- catch (err) {
139
- console.error(`[symbol-extractor] Failed to init ${this.languageId}:`, err);
140
- return false;
141
- }
142
- }
143
- /**
144
- * Extract symbols from a parsed tree-sitter tree
145
- */
146
- extract(
147
- // biome-ignore lint/suspicious/noExplicitAny: Tree type
148
- tree, filePath, content) {
149
- const symbols = [];
150
- const refs = [];
151
- const relativePath = path.relative(process.cwd(), filePath);
152
- // Extract definitions
153
- const defMatches = this.defQuery.matches(tree.rootNode);
154
- for (const match of defMatches) {
155
- const symbol = this.parseDefMatch(match, relativePath, content);
156
- if (symbol)
157
- symbols.push(symbol);
158
- }
159
- // Extract references
160
- const refMatches = this.refQuery.matches(tree.rootNode);
161
- for (const match of refMatches) {
162
- const ref = this.parseRefMatch(match, relativePath);
163
- if (ref)
164
- refs.push(ref);
165
- }
166
- return { symbols, refs };
167
- }
168
- // biome-ignore lint/suspicious/noExplicitAny: Match type
169
- parseDefMatch(match, filePath, content) {
170
- const captures = {};
171
- for (const capture of match.captures) {
172
- captures[capture.name] = {
173
- text: capture.node.text,
174
- // biome-ignore lint/suspicious/noExplicitAny: Node type
175
- node: capture.node,
176
- };
177
- }
178
- // Determine kind and name
179
- let name;
180
- let kind;
181
- let params;
182
- let defNode;
183
- if (captures.funcName) {
184
- name = captures.funcName.text;
185
- kind = "function";
186
- params = captures.funcParams?.text;
187
- // biome-ignore lint/suspicious/noExplicitAny: Node type
188
- defNode = captures.funcDef?.node;
189
- }
190
- else if (captures.arrowName) {
191
- name = captures.arrowName.text;
192
- kind = "function";
193
- params = captures.arrowParams?.text;
194
- // biome-ignore lint/suspicious/noExplicitAny: Node type
195
- defNode = captures.arrowDef?.node;
196
- }
197
- else if (captures.className) {
198
- name = captures.className.text;
199
- kind = "class";
200
- // biome-ignore lint/suspicious/noExplicitAny: Node type
201
- defNode = captures.classDef?.node;
202
- }
203
- else if (captures.methodName) {
204
- name = captures.methodName.text;
205
- kind = "method";
206
- params = captures.methodParams?.text;
207
- // biome-ignore lint/suspicious/noExplicitAny: Node type
208
- defNode = captures.methodDef?.node;
209
- }
210
- else if (captures.interfaceName) {
211
- name = captures.interfaceName.text;
212
- kind = "interface";
213
- // biome-ignore lint/suspicious/noExplicitAny: Node type
214
- defNode = captures.interfaceDef?.node;
215
- }
216
- else if (captures.typeName) {
217
- name = captures.typeName.text;
218
- kind = "type";
219
- // biome-ignore lint/suspicious/noExplicitAny: Node type
220
- defNode = captures.typeDef?.node;
221
- }
222
- if (!name || !kind || !defNode)
223
- return null;
224
- // Check if exported (basic heuristic: has export keyword before it)
225
- const isExported = this.isExported(defNode, content);
226
- const signature = params ? this.extractSignature(params, kind) : undefined;
227
- return {
228
- id: `${filePath}:${name}`,
229
- name,
230
- kind,
231
- filePath,
232
- line: defNode.startPosition.row + 1,
233
- column: defNode.startPosition.column + 1,
234
- signature,
235
- isExported,
236
- };
237
- }
238
- // biome-ignore lint/suspicious/noExplicitAny: Match type
239
- parseRefMatch(match, filePath) {
240
- let name;
241
- let refNode;
242
- for (const capture of match.captures) {
243
- if (capture.name.endsWith("Ident") ||
244
- capture.name.endsWith("Method") ||
245
- capture.name.endsWith("Field")) {
246
- name = capture.node.text;
247
- // biome-ignore lint/suspicious/noExplicitAny: Node type
248
- refNode = capture.node;
249
- }
250
- if (capture.name.endsWith("Ref") && !refNode) {
251
- // biome-ignore lint/suspicious/noExplicitAny: Node type
252
- refNode = capture.node;
253
- }
254
- }
255
- if (!name || !refNode)
256
- return null;
257
- return {
258
- symbolId: `${filePath}:${name}`, // Will be resolved later
259
- filePath,
260
- line: refNode.startPosition.row + 1,
261
- column: refNode.startPosition.column + 1,
262
- };
263
- }
264
- // biome-ignore lint/suspicious/noExplicitAny: Node type
265
- isExported(node, content) {
266
- // Simple heuristic: check for "export" keyword before the node
267
- const lines = content.split("\n");
268
- const lineIdx = node.startPosition.row;
269
- const line = lines[lineIdx] || "";
270
- return line.includes("export") || this.hasExportModifier(node, content);
271
- }
272
- // biome-ignore lint/suspicious/noExplicitAny: Node type
273
- hasExportModifier(_node, _content) {
274
- // TODO: Implement proper export modifier detection
275
- // For now, use simple line-based check
276
- return false;
277
- }
278
- extractSignature(paramsText, kind) {
279
- if (kind === "function" || kind === "method") {
280
- // Clean up params: remove comments, normalize whitespace
281
- return paramsText
282
- .replace(/\/\*[\s\S]*?\*\//g, "")
283
- .replace(/\/\/.*$/gm, "")
284
- .replace(/\s+/g, " ")
285
- .trim();
286
- }
287
- return undefined;
288
- }
289
- }