@aiready/ast-mcp-server 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -99
- package/dist/chunk-PRWMQQYW.js +80 -0
- package/dist/chunk-PRWMQQYW.js.map +1 -0
- package/dist/index.cjs +651 -265
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +525 -265
- package/dist/index.js.map +1 -1
- package/dist/search-code-V3LACKQ6.js +7 -0
- package/dist/search-code-V3LACKQ6.js.map +1 -0
- package/dist/worker/ast-worker.cjs +158 -0
- package/dist/worker/ast-worker.cjs.map +1 -0
- package/dist/worker/ast-worker.d.cts +2 -0
- package/dist/worker/ast-worker.d.ts +2 -0
- package/dist/worker/ast-worker.js +156 -0
- package/dist/worker/ast-worker.js.map +1 -0
- package/package.json +2 -1
package/dist/index.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,17 +30,121 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
33
|
+
// ../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js
|
|
34
|
+
var getImportMetaUrl, importMetaUrl;
|
|
35
|
+
var init_cjs_shims = __esm({
|
|
36
|
+
"../../node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js"() {
|
|
37
|
+
"use strict";
|
|
38
|
+
getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
39
|
+
importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// src/security.ts
|
|
44
|
+
function resolveWorkspaceRoot() {
|
|
45
|
+
return process.env.AST_WORKSPACE_ROOT || process.cwd();
|
|
46
|
+
}
|
|
47
|
+
function validateWorkspacePath(inputPath) {
|
|
48
|
+
const root = resolveWorkspaceRoot();
|
|
49
|
+
const resolved = import_path.default.resolve(root, inputPath);
|
|
50
|
+
const normalized = import_path.default.normalize(resolved);
|
|
51
|
+
if (!normalized.startsWith(root)) {
|
|
52
|
+
throw new Error(
|
|
53
|
+
`Path traversal detected: ${inputPath} escapes workspace root`
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
if (normalized.includes("\0")) {
|
|
57
|
+
throw new Error("Path contains null bytes");
|
|
58
|
+
}
|
|
59
|
+
return normalized;
|
|
60
|
+
}
|
|
61
|
+
var import_path;
|
|
62
|
+
var init_security = __esm({
|
|
63
|
+
"src/security.ts"() {
|
|
64
|
+
"use strict";
|
|
65
|
+
init_cjs_shims();
|
|
66
|
+
import_path = __toESM(require("path"), 1);
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// src/tools/search-code.ts
|
|
71
|
+
var search_code_exports = {};
|
|
72
|
+
__export(search_code_exports, {
|
|
73
|
+
searchCode: () => searchCode
|
|
74
|
+
});
|
|
75
|
+
async function searchCode(pattern, searchPath, filePattern, limit = 50, regex = true) {
|
|
76
|
+
const safePath = validateWorkspacePath(searchPath);
|
|
77
|
+
const args = [
|
|
78
|
+
"--json",
|
|
79
|
+
"--max-count",
|
|
80
|
+
limit.toString(),
|
|
81
|
+
"--max-columns",
|
|
82
|
+
"500"
|
|
83
|
+
];
|
|
84
|
+
if (!regex) {
|
|
85
|
+
args.push("--fixed-strings");
|
|
86
|
+
}
|
|
87
|
+
args.push(pattern, safePath);
|
|
88
|
+
if (filePattern) {
|
|
89
|
+
args.push("--glob", filePattern);
|
|
90
|
+
}
|
|
91
|
+
args.push("--glob", "!**/node_modules/**");
|
|
92
|
+
args.push("--glob", "!**/dist/**");
|
|
93
|
+
args.push("--glob", "!**/.git/**");
|
|
94
|
+
try {
|
|
95
|
+
const { stdout } = await execFileAsync(import_ripgrep.rgPath, args);
|
|
96
|
+
const lines = stdout.split("\n").filter(Boolean);
|
|
97
|
+
const results = [];
|
|
98
|
+
for (const line of lines) {
|
|
99
|
+
const data = JSON.parse(line);
|
|
100
|
+
if (data.type === "match") {
|
|
101
|
+
const file = data.data.path.text;
|
|
102
|
+
const lineNumber = data.data.line_number;
|
|
103
|
+
const submatches = data.data.submatches;
|
|
104
|
+
for (const submatch of submatches) {
|
|
105
|
+
results.push({
|
|
106
|
+
file,
|
|
107
|
+
line: lineNumber,
|
|
108
|
+
column: submatch.start,
|
|
109
|
+
text: data.data.lines.text.trim()
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return results.slice(0, limit);
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (error.code === 1) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
var import_child_process, import_util, import_ripgrep, execFileAsync;
|
|
123
|
+
var init_search_code = __esm({
|
|
124
|
+
"src/tools/search-code.ts"() {
|
|
125
|
+
"use strict";
|
|
126
|
+
init_cjs_shims();
|
|
127
|
+
import_child_process = require("child_process");
|
|
128
|
+
import_util = require("util");
|
|
129
|
+
import_ripgrep = require("@vscode/ripgrep");
|
|
130
|
+
init_security();
|
|
131
|
+
execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
30
135
|
// src/index.ts
|
|
31
136
|
var index_exports = {};
|
|
32
137
|
__export(index_exports, {
|
|
33
138
|
ASTExplorerServer: () => ASTExplorerServer
|
|
34
139
|
});
|
|
35
140
|
module.exports = __toCommonJS(index_exports);
|
|
141
|
+
init_cjs_shims();
|
|
36
142
|
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
37
143
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
38
144
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
39
145
|
|
|
40
146
|
// src/schemas.ts
|
|
147
|
+
init_cjs_shims();
|
|
41
148
|
var import_zod = require("zod");
|
|
42
149
|
var ResolveDefinitionSchema = import_zod.z.object({
|
|
43
150
|
symbol: import_zod.z.string().describe(
|
|
@@ -61,10 +168,11 @@ var GetFileStructureSchema = import_zod.z.object({
|
|
|
61
168
|
file: import_zod.z.string().describe("Absolute path to the file to analyze")
|
|
62
169
|
});
|
|
63
170
|
var SearchCodeSchema = import_zod.z.object({
|
|
64
|
-
pattern: import_zod.z.string().describe("Search pattern (regex)"),
|
|
171
|
+
pattern: import_zod.z.string().describe("Search pattern (regex by default)"),
|
|
65
172
|
path: import_zod.z.string().describe("Directory to search in"),
|
|
66
173
|
filePattern: import_zod.z.string().optional().describe('Glob filter (e.g., "*.ts")'),
|
|
67
|
-
limit: import_zod.z.number().optional().default(50).describe("Max matches to return")
|
|
174
|
+
limit: import_zod.z.number().optional().default(50).describe("Max matches to return"),
|
|
175
|
+
regex: import_zod.z.boolean().optional().default(true).describe("Use regex mode (default true)")
|
|
68
176
|
});
|
|
69
177
|
var GetSymbolDocsSchema = import_zod.z.object({
|
|
70
178
|
symbol: import_zod.z.string().describe("Symbol name to get documentation for"),
|
|
@@ -74,189 +182,555 @@ var BuildSymbolIndexSchema = import_zod.z.object({
|
|
|
74
182
|
path: import_zod.z.string().describe("Project root directory to index")
|
|
75
183
|
});
|
|
76
184
|
|
|
185
|
+
// src/tools/resolve-definition.ts
|
|
186
|
+
init_cjs_shims();
|
|
187
|
+
|
|
77
188
|
// src/adapters/typescript-adapter.ts
|
|
78
|
-
|
|
189
|
+
init_cjs_shims();
|
|
190
|
+
var import_ts_morph3 = require("ts-morph");
|
|
191
|
+
var import_fs3 = __toESM(require("fs"), 1);
|
|
79
192
|
|
|
80
193
|
// src/project-manager.ts
|
|
194
|
+
init_cjs_shims();
|
|
81
195
|
var import_ts_morph = require("ts-morph");
|
|
82
|
-
var
|
|
196
|
+
var import_path2 = __toESM(require("path"), 1);
|
|
83
197
|
var import_fs = __toESM(require("fs"), 1);
|
|
84
198
|
var import_glob = require("glob");
|
|
199
|
+
init_security();
|
|
85
200
|
var ProjectManager = class {
|
|
86
201
|
projects = /* @__PURE__ */ new Map();
|
|
87
202
|
tsconfigCache = /* @__PURE__ */ new Map();
|
|
203
|
+
accessOrder = [];
|
|
204
|
+
// MRU at front
|
|
205
|
+
maxProjects = 4;
|
|
88
206
|
/**
|
|
89
207
|
* Find all tsconfig.json files in a directory (recursive)
|
|
90
208
|
*/
|
|
91
209
|
async findTsConfigs(rootDir) {
|
|
92
|
-
|
|
93
|
-
|
|
210
|
+
const safeRoot = validateWorkspacePath(rootDir);
|
|
211
|
+
if (this.tsconfigCache.has(safeRoot)) {
|
|
212
|
+
return this.tsconfigCache.get(safeRoot);
|
|
94
213
|
}
|
|
95
214
|
const configs = await (0, import_glob.glob)("**/tsconfig.json", {
|
|
96
|
-
cwd:
|
|
215
|
+
cwd: safeRoot,
|
|
97
216
|
absolute: true,
|
|
98
217
|
ignore: ["**/node_modules/**", "**/dist/**"]
|
|
99
218
|
});
|
|
100
|
-
this.tsconfigCache.set(
|
|
219
|
+
this.tsconfigCache.set(safeRoot, configs);
|
|
101
220
|
return configs;
|
|
102
221
|
}
|
|
103
222
|
/**
|
|
104
|
-
*
|
|
105
|
-
*/
|
|
106
|
-
async getProjectForFile(filePath) {
|
|
107
|
-
const tsconfigPath = await this.findNearestTsConfig(filePath);
|
|
108
|
-
if (!tsconfigPath) return void 0;
|
|
109
|
-
return this.getOrCreateProject(tsconfigPath);
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Get or create a Project for a tsconfig path
|
|
223
|
+
* Ensure a Project exists for a given tsconfig path, managing LRU cache
|
|
113
224
|
*/
|
|
114
|
-
|
|
225
|
+
ensureProject(tsconfigPath) {
|
|
226
|
+
this.checkMemoryPressure();
|
|
115
227
|
if (this.projects.has(tsconfigPath)) {
|
|
228
|
+
this.moveToFront(tsconfigPath);
|
|
116
229
|
return this.projects.get(tsconfigPath);
|
|
117
230
|
}
|
|
231
|
+
while (this.projects.size >= this.maxProjects) {
|
|
232
|
+
const oldest = this.accessOrder.pop();
|
|
233
|
+
this.disposeProject(oldest);
|
|
234
|
+
}
|
|
118
235
|
const project = new import_ts_morph.Project({
|
|
119
236
|
tsConfigFilePath: tsconfigPath,
|
|
120
|
-
skipAddingFilesFromTsConfig:
|
|
237
|
+
skipAddingFilesFromTsConfig: true
|
|
238
|
+
// KEY: don't load all files
|
|
121
239
|
});
|
|
122
240
|
this.projects.set(tsconfigPath, project);
|
|
241
|
+
this.accessOrder.unshift(tsconfigPath);
|
|
123
242
|
return project;
|
|
124
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* Move a tsconfig path to the front of the access order (MRU)
|
|
246
|
+
*/
|
|
247
|
+
moveToFront(tsconfigPath) {
|
|
248
|
+
const index = this.accessOrder.indexOf(tsconfigPath);
|
|
249
|
+
if (index > -1) {
|
|
250
|
+
this.accessOrder.splice(index, 1);
|
|
251
|
+
this.accessOrder.unshift(tsconfigPath);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
checkMemoryPressure() {
|
|
255
|
+
const heapUsed = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
256
|
+
const maxHeap = parseInt(process.env.AST_MAX_HEAP_MB || "1536", 10);
|
|
257
|
+
while (heapUsed > maxHeap && this.projects.size > 1) {
|
|
258
|
+
const oldest = this.accessOrder.pop();
|
|
259
|
+
this.disposeProject(oldest);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
disposeProject(tsconfigPath) {
|
|
263
|
+
const project = this.projects.get(tsconfigPath);
|
|
264
|
+
if (project) {
|
|
265
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
266
|
+
project.removeSourceFile(sourceFile);
|
|
267
|
+
}
|
|
268
|
+
this.projects.delete(tsconfigPath);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
125
271
|
/**
|
|
126
272
|
* Find the nearest tsconfig.json for a file
|
|
127
273
|
*/
|
|
128
274
|
async findNearestTsConfig(filePath) {
|
|
129
|
-
|
|
130
|
-
|
|
275
|
+
const safePath = validateWorkspacePath(filePath);
|
|
276
|
+
let currentDir = import_path2.default.dirname(safePath);
|
|
277
|
+
const root = import_path2.default.parse(currentDir).root;
|
|
131
278
|
while (currentDir !== root) {
|
|
132
|
-
const tsconfigPath =
|
|
279
|
+
const tsconfigPath = import_path2.default.join(currentDir, "tsconfig.json");
|
|
133
280
|
if (import_fs.default.existsSync(tsconfigPath)) {
|
|
134
281
|
return tsconfigPath;
|
|
135
282
|
}
|
|
136
|
-
currentDir =
|
|
283
|
+
currentDir = import_path2.default.dirname(currentDir);
|
|
137
284
|
}
|
|
138
285
|
return void 0;
|
|
139
286
|
}
|
|
140
287
|
/**
|
|
141
|
-
* Get all
|
|
288
|
+
* Get all tsconfigs for a path
|
|
142
289
|
*/
|
|
143
290
|
async getProjectsForPath(rootDir) {
|
|
144
|
-
|
|
145
|
-
return configs.map((config) => this.getOrCreateProject(config));
|
|
291
|
+
return this.findTsConfigs(rootDir);
|
|
146
292
|
}
|
|
147
293
|
/**
|
|
148
294
|
* Dispose all projects to free memory
|
|
149
295
|
*/
|
|
150
296
|
disposeAll() {
|
|
151
|
-
for (const
|
|
152
|
-
|
|
297
|
+
for (const [key] of this.projects) {
|
|
298
|
+
this.disposeProject(key);
|
|
153
299
|
}
|
|
154
|
-
this.
|
|
300
|
+
this.accessOrder = [];
|
|
155
301
|
}
|
|
156
302
|
};
|
|
157
303
|
var projectManager = new ProjectManager();
|
|
158
304
|
|
|
159
|
-
// src/
|
|
160
|
-
|
|
305
|
+
// src/index/symbol-index.ts
|
|
306
|
+
init_cjs_shims();
|
|
307
|
+
init_security();
|
|
308
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
309
|
+
var import_crypto = __toESM(require("crypto"), 1);
|
|
310
|
+
var import_path3 = __toESM(require("path"), 1);
|
|
311
|
+
var import_ts_morph2 = require("ts-morph");
|
|
312
|
+
var SymbolIndex = class {
|
|
313
|
+
index = {};
|
|
314
|
+
getCachePath(rootDir) {
|
|
315
|
+
const hash = import_crypto.default.createHash("sha256").update(rootDir).digest("hex").slice(0, 12);
|
|
316
|
+
return import_path3.default.join(
|
|
317
|
+
process.platform === "win32" ? process.env.TEMP || "c:/temp" : "/tmp",
|
|
318
|
+
`ast-index-${hash}.json`
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
isCacheValid(cached, rootDir) {
|
|
322
|
+
if (cached.rootDir !== rootDir) return false;
|
|
323
|
+
for (const [file, cachedMtime] of Object.entries(cached.fileHashes)) {
|
|
324
|
+
if (!import_fs2.default.existsSync(file)) return false;
|
|
325
|
+
if (import_fs2.default.statSync(file).mtimeMs !== cachedMtime) return false;
|
|
326
|
+
}
|
|
327
|
+
return true;
|
|
328
|
+
}
|
|
329
|
+
computeStats(cache, duration_ms, memory_mb) {
|
|
330
|
+
const files = Object.keys(cache.fileHashes).length;
|
|
331
|
+
let functions = 0;
|
|
332
|
+
let classes = 0;
|
|
333
|
+
let interfaces = 0;
|
|
334
|
+
let types = 0;
|
|
335
|
+
for (const entries of Object.values(cache.symbols)) {
|
|
336
|
+
for (const entry of entries) {
|
|
337
|
+
if (entry.kind === "function" || entry.kind === "method") functions++;
|
|
338
|
+
if (entry.kind === "class") classes++;
|
|
339
|
+
if (entry.kind === "interface") interfaces++;
|
|
340
|
+
if (entry.kind === "type_alias") types++;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
indexed: {
|
|
345
|
+
files,
|
|
346
|
+
functions,
|
|
347
|
+
classes,
|
|
348
|
+
interfaces,
|
|
349
|
+
types
|
|
350
|
+
},
|
|
351
|
+
duration_ms: duration_ms || 0,
|
|
352
|
+
memory_mb: memory_mb || 0
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
mapKind(node) {
|
|
356
|
+
if (import_ts_morph2.Node.isClassDeclaration(node)) return "class";
|
|
357
|
+
if (import_ts_morph2.Node.isFunctionDeclaration(node)) return "function";
|
|
358
|
+
if (import_ts_morph2.Node.isInterfaceDeclaration(node)) return "interface";
|
|
359
|
+
if (import_ts_morph2.Node.isTypeAliasDeclaration(node)) return "type_alias";
|
|
360
|
+
if (import_ts_morph2.Node.isEnumDeclaration(node)) return "enum";
|
|
361
|
+
if (import_ts_morph2.Node.isVariableDeclaration(node)) return "variable";
|
|
362
|
+
if (import_ts_morph2.Node.isMethodDeclaration(node)) return "method";
|
|
363
|
+
if (import_ts_morph2.Node.isPropertyDeclaration(node)) return "property";
|
|
364
|
+
if (import_ts_morph2.Node.isParameterDeclaration(node)) return "parameter";
|
|
365
|
+
return "variable";
|
|
366
|
+
}
|
|
161
367
|
/**
|
|
162
|
-
*
|
|
368
|
+
* Build/Warm the index for a given path
|
|
163
369
|
*/
|
|
164
|
-
async
|
|
165
|
-
const
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
370
|
+
async buildIndex(rootDir) {
|
|
371
|
+
const startTime = Date.now();
|
|
372
|
+
const safeRoot = validateWorkspacePath(rootDir);
|
|
373
|
+
const cachePath = this.getCachePath(safeRoot);
|
|
374
|
+
if (import_fs2.default.existsSync(cachePath)) {
|
|
375
|
+
try {
|
|
376
|
+
const cached = JSON.parse(
|
|
377
|
+
import_fs2.default.readFileSync(cachePath, "utf-8")
|
|
378
|
+
);
|
|
379
|
+
if (this.isCacheValid(cached, safeRoot)) {
|
|
380
|
+
this.index = cached.symbols;
|
|
381
|
+
return this.computeStats(
|
|
382
|
+
cached,
|
|
383
|
+
Date.now() - startTime,
|
|
384
|
+
process.memoryUsage().heapUsed / 1024 / 1024
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
} catch (e) {
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
const tsconfigs = await projectManager.getProjectsForPath(safeRoot);
|
|
391
|
+
const symbols = {};
|
|
392
|
+
const fileHashes = {};
|
|
393
|
+
for (const config of tsconfigs) {
|
|
394
|
+
const project = projectManager.ensureProject(config);
|
|
395
|
+
project.addSourceFilesFromTsConfig(config);
|
|
396
|
+
for (const sourceFile of project.getSourceFiles()) {
|
|
397
|
+
const filePath = sourceFile.getFilePath();
|
|
398
|
+
try {
|
|
399
|
+
fileHashes[filePath] = import_fs2.default.statSync(filePath).mtimeMs;
|
|
400
|
+
} catch {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
for (const [name, decls] of sourceFile.getExportedDeclarations()) {
|
|
404
|
+
for (const decl of decls) {
|
|
405
|
+
const entry = {
|
|
406
|
+
name,
|
|
407
|
+
kind: this.mapKind(decl),
|
|
408
|
+
file: filePath,
|
|
409
|
+
line: decl.getStartLineNumber(),
|
|
410
|
+
column: decl.getStart() - decl.getStartLinePos(),
|
|
411
|
+
exported: true
|
|
412
|
+
};
|
|
413
|
+
(symbols[name] ||= []).push(entry);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
for (const fn of sourceFile.getFunctions()) {
|
|
417
|
+
const name = fn.getName();
|
|
418
|
+
if (name && !symbols[name]?.some(
|
|
419
|
+
(s) => s.file === filePath && s.line === fn.getStartLineNumber()
|
|
420
|
+
)) {
|
|
421
|
+
const entry = {
|
|
422
|
+
name,
|
|
423
|
+
kind: "function",
|
|
424
|
+
file: filePath,
|
|
425
|
+
line: fn.getStartLineNumber(),
|
|
426
|
+
column: fn.getStart() - fn.getStartLinePos(),
|
|
427
|
+
exported: false
|
|
428
|
+
};
|
|
429
|
+
(symbols[name] ||= []).push(entry);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
for (const cls of sourceFile.getClasses()) {
|
|
433
|
+
const name = cls.getName();
|
|
434
|
+
if (name && !symbols[name]?.some(
|
|
435
|
+
(s) => s.file === filePath && s.line === cls.getStartLineNumber()
|
|
436
|
+
)) {
|
|
437
|
+
const entry = {
|
|
438
|
+
name,
|
|
439
|
+
kind: "class",
|
|
440
|
+
file: filePath,
|
|
441
|
+
line: cls.getStartLineNumber(),
|
|
442
|
+
column: cls.getStart() - cls.getStartLinePos(),
|
|
443
|
+
exported: false
|
|
444
|
+
};
|
|
445
|
+
(symbols[name] ||= []).push(entry);
|
|
175
446
|
}
|
|
176
447
|
}
|
|
177
448
|
}
|
|
178
449
|
}
|
|
179
|
-
|
|
450
|
+
const cache = {
|
|
451
|
+
version: 1,
|
|
452
|
+
rootDir: safeRoot,
|
|
453
|
+
builtAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
454
|
+
fileHashes,
|
|
455
|
+
symbols
|
|
456
|
+
};
|
|
457
|
+
import_fs2.default.mkdirSync(import_path3.default.dirname(cachePath), { recursive: true });
|
|
458
|
+
import_fs2.default.writeFileSync(cachePath, JSON.stringify(cache));
|
|
459
|
+
this.index = symbols;
|
|
460
|
+
const duration = Date.now() - startTime;
|
|
461
|
+
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
462
|
+
return this.computeStats(cache, duration, Math.round(memoryUsage));
|
|
180
463
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
464
|
+
lookup(name) {
|
|
465
|
+
return this.index[name] || [];
|
|
466
|
+
}
|
|
467
|
+
lookupByFile(file) {
|
|
468
|
+
return Object.values(this.index).flat().filter((e) => e.file === file);
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
var symbolIndex = new SymbolIndex();
|
|
472
|
+
|
|
473
|
+
// src/adapters/typescript-adapter.ts
|
|
474
|
+
init_security();
|
|
475
|
+
|
|
476
|
+
// src/worker/pool.ts
|
|
477
|
+
init_cjs_shims();
|
|
478
|
+
var import_worker_threads = require("worker_threads");
|
|
479
|
+
var import_path4 = __toESM(require("path"), 1);
|
|
480
|
+
var import_url = require("url");
|
|
481
|
+
var WorkerPool = class {
|
|
482
|
+
constructor(poolSize) {
|
|
483
|
+
this.poolSize = poolSize;
|
|
484
|
+
}
|
|
485
|
+
workers = [];
|
|
486
|
+
available = [];
|
|
487
|
+
queue = [];
|
|
488
|
+
activeJobs = /* @__PURE__ */ new Map();
|
|
489
|
+
taskId = 0;
|
|
490
|
+
async init() {
|
|
491
|
+
const __dirname = import_path4.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
|
|
492
|
+
const workerPath = import_path4.default.join(__dirname, "ast-worker.js");
|
|
493
|
+
for (let i = 0; i < this.poolSize; i++) {
|
|
494
|
+
const worker = new import_worker_threads.Worker(workerPath);
|
|
495
|
+
worker.on("message", (msg) => this.handleResult(msg));
|
|
496
|
+
worker.on("error", (err) => this.handleWorkerError(worker, err));
|
|
497
|
+
this.workers.push(worker);
|
|
498
|
+
this.available.push(worker);
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
async execute(type, payload) {
|
|
502
|
+
return new Promise((resolve, reject) => {
|
|
503
|
+
const id = String(++this.taskId);
|
|
504
|
+
const task = { id, type, payload, resolve, reject };
|
|
505
|
+
const worker = this.available.pop();
|
|
506
|
+
if (worker) {
|
|
507
|
+
this.dispatch(worker, task);
|
|
508
|
+
} else {
|
|
509
|
+
this.queue.push(task);
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
dispatch(worker, task) {
|
|
514
|
+
this.activeJobs.set(task.id, task);
|
|
515
|
+
worker.postMessage({ id: task.id, type: task.type, payload: task.payload });
|
|
516
|
+
}
|
|
517
|
+
handleResult(msg) {
|
|
518
|
+
const task = this.activeJobs.get(msg.id);
|
|
519
|
+
if (!task) return;
|
|
520
|
+
this.activeJobs.delete(msg.id);
|
|
521
|
+
if (msg.error) {
|
|
522
|
+
task.reject(new Error(msg.error));
|
|
523
|
+
} else {
|
|
524
|
+
task.resolve(msg.result);
|
|
525
|
+
}
|
|
526
|
+
const worker = this.workers.find(
|
|
527
|
+
(w) => !this.available.includes(w) && ![...this.activeJobs.values()].some((t) => t.id === msg.id)
|
|
528
|
+
// simplistic
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
handleWorkerError(worker, err) {
|
|
532
|
+
const idx = this.workers.indexOf(worker);
|
|
533
|
+
if (idx !== -1) {
|
|
534
|
+
worker.terminate();
|
|
535
|
+
const __dirname = import_path4.default.dirname((0, import_url.fileURLToPath)(importMetaUrl));
|
|
536
|
+
const workerPath = import_path4.default.join(__dirname, "ast-worker.js");
|
|
537
|
+
const newWorker = new import_worker_threads.Worker(workerPath);
|
|
538
|
+
newWorker.on("message", (msg) => this.handleResult(msg));
|
|
539
|
+
newWorker.on("error", (e) => this.handleWorkerError(newWorker, e));
|
|
540
|
+
this.workers[idx] = newWorker;
|
|
541
|
+
this.available.push(newWorker);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
async terminate() {
|
|
545
|
+
await Promise.all(this.workers.map((w) => w.terminate()));
|
|
546
|
+
this.workers = [];
|
|
547
|
+
this.available = [];
|
|
548
|
+
}
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
// src/adapters/typescript-adapter.ts
|
|
552
|
+
var TypeScriptAdapter = class {
|
|
553
|
+
pool;
|
|
554
|
+
constructor() {
|
|
555
|
+
const poolSize = parseInt(process.env.AST_WORKER_POOL_SIZE || "2");
|
|
556
|
+
this.pool = new WorkerPool(poolSize);
|
|
557
|
+
}
|
|
558
|
+
async resolveDefinition(symbolName, path5) {
|
|
559
|
+
validateWorkspacePath(path5);
|
|
560
|
+
const indexHits = symbolIndex.lookup(symbolName);
|
|
561
|
+
if (indexHits.length > 0) {
|
|
562
|
+
const results = [];
|
|
563
|
+
for (const hit of indexHits) {
|
|
564
|
+
const tsconfig2 = await projectManager.findNearestTsConfig(hit.file);
|
|
565
|
+
if (tsconfig2) {
|
|
566
|
+
const project = projectManager.ensureProject(tsconfig2);
|
|
567
|
+
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
568
|
+
if (sourceFile) {
|
|
569
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
570
|
+
if (exported && exported.length > 0) {
|
|
571
|
+
results.push(this.mapToDefinitionLocation(exported[0]));
|
|
572
|
+
continue;
|
|
206
573
|
}
|
|
207
574
|
}
|
|
208
575
|
}
|
|
576
|
+
results.push({
|
|
577
|
+
file: hit.file,
|
|
578
|
+
line: hit.line,
|
|
579
|
+
column: hit.column,
|
|
580
|
+
kind: hit.kind,
|
|
581
|
+
snippet: "",
|
|
582
|
+
documentation: void 0
|
|
583
|
+
});
|
|
209
584
|
}
|
|
585
|
+
return results;
|
|
586
|
+
}
|
|
587
|
+
if (import_fs3.default.statSync(path5).isDirectory()) {
|
|
588
|
+
return [];
|
|
589
|
+
}
|
|
590
|
+
const tsconfig = await projectManager.findNearestTsConfig(path5);
|
|
591
|
+
if (!tsconfig) return [];
|
|
592
|
+
try {
|
|
593
|
+
const result = await this.pool.execute(
|
|
594
|
+
"resolve_definition",
|
|
595
|
+
{
|
|
596
|
+
tsconfig,
|
|
597
|
+
file: path5,
|
|
598
|
+
symbol: symbolName
|
|
599
|
+
}
|
|
600
|
+
);
|
|
601
|
+
return result;
|
|
602
|
+
} catch {
|
|
603
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
604
|
+
const sourceFile = project.addSourceFileAtPathIfExists(path5);
|
|
605
|
+
if (!sourceFile) return [];
|
|
606
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
607
|
+
if (!exported) return [];
|
|
608
|
+
return exported.map((decl) => this.mapToDefinitionLocation(decl));
|
|
210
609
|
}
|
|
211
|
-
const uniqueResults = this.deduplicateLocations(results);
|
|
212
|
-
return {
|
|
213
|
-
references: uniqueResults.slice(offset, offset + limit),
|
|
214
|
-
total_count: uniqueResults.length
|
|
215
|
-
};
|
|
216
610
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const
|
|
611
|
+
async findReferences(symbolName, path5, limit = 50, offset = 0) {
|
|
612
|
+
validateWorkspacePath(path5);
|
|
613
|
+
const hits = symbolIndex.lookup(symbolName);
|
|
614
|
+
if (hits.length === 0) return { references: [], total_count: 0 };
|
|
615
|
+
const hit = hits[0];
|
|
616
|
+
const tsconfig = await projectManager.findNearestTsConfig(hit.file);
|
|
617
|
+
if (!tsconfig) return { references: [], total_count: 0 };
|
|
618
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
619
|
+
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
620
|
+
if (!sourceFile) return { references: [], total_count: 0 };
|
|
621
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
622
|
+
if (!exported || exported.length === 0)
|
|
623
|
+
return { references: [], total_count: 0 };
|
|
624
|
+
const targetNode = exported[0];
|
|
625
|
+
try {
|
|
626
|
+
const { searchCode: searchCode2 } = await Promise.resolve().then(() => (init_search_code(), search_code_exports));
|
|
627
|
+
const searchResults = await searchCode2(
|
|
628
|
+
symbolName,
|
|
629
|
+
path5,
|
|
630
|
+
"*.{ts,tsx,js,jsx}",
|
|
631
|
+
1e3,
|
|
632
|
+
false
|
|
633
|
+
);
|
|
634
|
+
const filesToLoad = [...new Set(searchResults.map((r) => r.file))];
|
|
635
|
+
for (const file of filesToLoad) {
|
|
636
|
+
project.addSourceFileAtPathIfExists(file);
|
|
637
|
+
}
|
|
638
|
+
} catch (_e) {
|
|
639
|
+
}
|
|
640
|
+
const refSymbols = targetNode.findReferences?.();
|
|
641
|
+
if (!refSymbols) return { references: [], total_count: 0 };
|
|
222
642
|
const results = [];
|
|
223
|
-
for (const
|
|
224
|
-
const
|
|
225
|
-
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
);
|
|
234
|
-
results.push({
|
|
235
|
-
file: sourceFile2.getFilePath(),
|
|
236
|
-
line: lineAndColumn.line,
|
|
237
|
-
column: lineAndColumn.column,
|
|
238
|
-
text: impl.getNode().getParent()?.getText() || impl.getNode().getText()
|
|
239
|
-
});
|
|
240
|
-
}
|
|
241
|
-
}
|
|
643
|
+
for (const refSymbol of refSymbols) {
|
|
644
|
+
for (const ref of refSymbol.getReferences()) {
|
|
645
|
+
const sf = ref.getSourceFile();
|
|
646
|
+
const lc = sf.getLineAndColumnAtPos(ref.getTextSpan().getStart());
|
|
647
|
+
results.push({
|
|
648
|
+
file: sf.getFilePath(),
|
|
649
|
+
line: lc.line,
|
|
650
|
+
column: lc.column,
|
|
651
|
+
text: ref.getNode().getParent()?.getText() || ref.getNode().getText()
|
|
652
|
+
});
|
|
242
653
|
}
|
|
243
654
|
}
|
|
244
|
-
const
|
|
655
|
+
const unique = this.deduplicateLocations(results);
|
|
245
656
|
return {
|
|
246
|
-
|
|
247
|
-
total_count:
|
|
657
|
+
references: unique.slice(offset, offset + limit),
|
|
658
|
+
total_count: unique.length
|
|
248
659
|
};
|
|
249
660
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
661
|
+
async findImplementations(symbolName, path5, limit = 50, offset = 0) {
|
|
662
|
+
validateWorkspacePath(path5);
|
|
663
|
+
const hits = symbolIndex.lookup(symbolName);
|
|
664
|
+
if (hits.length === 0) return { implementations: [], total_count: 0 };
|
|
665
|
+
const hit = hits[0];
|
|
666
|
+
const tsconfig = await projectManager.findNearestTsConfig(hit.file);
|
|
667
|
+
if (!tsconfig) return { implementations: [], total_count: 0 };
|
|
668
|
+
try {
|
|
669
|
+
const result = await this.pool.execute("find_implementations", {
|
|
670
|
+
tsconfig,
|
|
671
|
+
file: hit.file,
|
|
672
|
+
symbol: symbolName
|
|
673
|
+
});
|
|
674
|
+
return {
|
|
675
|
+
implementations: result.implementations.slice(offset, offset + limit),
|
|
676
|
+
total_count: result.total_count
|
|
677
|
+
};
|
|
678
|
+
} catch {
|
|
679
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
680
|
+
const sourceFile = project.addSourceFileAtPathIfExists(hit.file);
|
|
681
|
+
if (!sourceFile) return { implementations: [], total_count: 0 };
|
|
682
|
+
const exported = sourceFile.getExportedDeclarations().get(symbolName);
|
|
683
|
+
if (!exported || exported.length === 0)
|
|
684
|
+
return { implementations: [], total_count: 0 };
|
|
685
|
+
const targetNode = exported[0];
|
|
686
|
+
if (!import_ts_morph3.Node.isClassDeclaration(targetNode) && !import_ts_morph3.Node.isInterfaceDeclaration(targetNode)) {
|
|
687
|
+
return { implementations: [], total_count: 0 };
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
const { searchCode: searchCode2 } = await Promise.resolve().then(() => (init_search_code(), search_code_exports));
|
|
691
|
+
const searchResults = await searchCode2(
|
|
692
|
+
symbolName,
|
|
693
|
+
path5,
|
|
694
|
+
"*.{ts,tsx,js,jsx}",
|
|
695
|
+
1e3,
|
|
696
|
+
false
|
|
697
|
+
);
|
|
698
|
+
const filesToLoad = [...new Set(searchResults.map((r) => r.file))];
|
|
699
|
+
for (const file of filesToLoad) {
|
|
700
|
+
project.addSourceFileAtPathIfExists(file);
|
|
701
|
+
}
|
|
702
|
+
} catch (_e) {
|
|
703
|
+
}
|
|
704
|
+
const results = [];
|
|
705
|
+
const implementations = targetNode.getImplementations?.();
|
|
706
|
+
if (implementations) {
|
|
707
|
+
for (const impl of implementations) {
|
|
708
|
+
const sf = impl.getSourceFile();
|
|
709
|
+
const lc = sf.getLineAndColumnAtPos(impl.getTextSpan().getStart());
|
|
710
|
+
results.push({
|
|
711
|
+
file: sf.getFilePath(),
|
|
712
|
+
line: lc.line,
|
|
713
|
+
column: lc.column,
|
|
714
|
+
text: impl.getNode().getParent()?.getText() || impl.getNode().getText()
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
const unique = this.deduplicateLocations(results);
|
|
719
|
+
return {
|
|
720
|
+
implementations: unique.slice(offset, offset + limit),
|
|
721
|
+
total_count: unique.length
|
|
722
|
+
};
|
|
723
|
+
}
|
|
724
|
+
}
|
|
253
725
|
async getFileStructure(filePath) {
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
726
|
+
const safePath = validateWorkspacePath(filePath);
|
|
727
|
+
const tsconfig = await projectManager.findNearestTsConfig(safePath);
|
|
728
|
+
if (!tsconfig) return void 0;
|
|
729
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
730
|
+
const sourceFile = project.addSourceFileAtPathIfExists(safePath);
|
|
257
731
|
if (!sourceFile) return void 0;
|
|
258
732
|
const structure = {
|
|
259
|
-
file:
|
|
733
|
+
file: safePath,
|
|
260
734
|
imports: sourceFile.getImportDeclarations().map((imp) => ({
|
|
261
735
|
module: imp.getModuleSpecifierValue(),
|
|
262
736
|
names: imp.getNamedImports().map((ni) => ni.getName())
|
|
@@ -273,9 +747,9 @@ var TypeScriptAdapter = class {
|
|
|
273
747
|
};
|
|
274
748
|
return structure;
|
|
275
749
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
750
|
+
async shutdown() {
|
|
751
|
+
await this.pool.terminate();
|
|
752
|
+
}
|
|
279
753
|
mapToDefinitionLocation(node) {
|
|
280
754
|
const sourceFile = node.getSourceFile();
|
|
281
755
|
const lineAndColumn = sourceFile.getLineAndColumnAtPos(node.getStart());
|
|
@@ -288,34 +762,25 @@ var TypeScriptAdapter = class {
|
|
|
288
762
|
documentation: this.getJsDoc(node)
|
|
289
763
|
};
|
|
290
764
|
}
|
|
291
|
-
/**
|
|
292
|
-
* Helper: Map ts-morph Node to SymbolKind
|
|
293
|
-
*/
|
|
294
765
|
mapNodeToSymbolKind(node) {
|
|
295
|
-
if (
|
|
296
|
-
if (
|
|
297
|
-
if (
|
|
298
|
-
if (
|
|
299
|
-
if (
|
|
300
|
-
if (
|
|
301
|
-
if (
|
|
302
|
-
if (
|
|
303
|
-
if (
|
|
766
|
+
if (import_ts_morph3.Node.isClassDeclaration(node)) return "class";
|
|
767
|
+
if (import_ts_morph3.Node.isFunctionDeclaration(node)) return "function";
|
|
768
|
+
if (import_ts_morph3.Node.isInterfaceDeclaration(node)) return "interface";
|
|
769
|
+
if (import_ts_morph3.Node.isTypeAliasDeclaration(node)) return "type_alias";
|
|
770
|
+
if (import_ts_morph3.Node.isEnumDeclaration(node)) return "enum";
|
|
771
|
+
if (import_ts_morph3.Node.isVariableDeclaration(node)) return "variable";
|
|
772
|
+
if (import_ts_morph3.Node.isMethodDeclaration(node)) return "method";
|
|
773
|
+
if (import_ts_morph3.Node.isPropertyDeclaration(node)) return "property";
|
|
774
|
+
if (import_ts_morph3.Node.isParameterDeclaration(node)) return "parameter";
|
|
304
775
|
return "variable";
|
|
305
776
|
}
|
|
306
|
-
/**
|
|
307
|
-
* Helper: Map Symbol to SymbolKind
|
|
308
|
-
*/
|
|
309
777
|
mapSymbolKind(symbol) {
|
|
310
778
|
const decls = symbol.getDeclarations();
|
|
311
779
|
if (decls.length > 0) return this.mapNodeToSymbolKind(decls[0]);
|
|
312
780
|
return "variable";
|
|
313
781
|
}
|
|
314
|
-
/**
|
|
315
|
-
* Helper: Get JSDoc from Node
|
|
316
|
-
*/
|
|
317
782
|
getJsDoc(node) {
|
|
318
|
-
if (
|
|
783
|
+
if (import_ts_morph3.Node.isJSDocable(node)) {
|
|
319
784
|
const docs = node.getJsDocs();
|
|
320
785
|
if (docs.length > 0) {
|
|
321
786
|
return docs[0].getCommentText();
|
|
@@ -323,11 +788,8 @@ var TypeScriptAdapter = class {
|
|
|
323
788
|
}
|
|
324
789
|
return void 0;
|
|
325
790
|
}
|
|
326
|
-
/**
|
|
327
|
-
* Helper: Get full JSDoc info (with tags)
|
|
328
|
-
*/
|
|
329
791
|
getSymbolDocs(node) {
|
|
330
|
-
if (
|
|
792
|
+
if (import_ts_morph3.Node.isJSDocable(node)) {
|
|
331
793
|
const docs = node.getJsDocs();
|
|
332
794
|
if (docs.length > 0) {
|
|
333
795
|
const doc = docs[0];
|
|
@@ -390,9 +852,6 @@ var TypeScriptAdapter = class {
|
|
|
390
852
|
members: enm.getMembers().map((m) => m.getName())
|
|
391
853
|
};
|
|
392
854
|
}
|
|
393
|
-
/**
|
|
394
|
-
* Helper: Deduplicate locations
|
|
395
|
-
*/
|
|
396
855
|
deduplicateLocations(locations) {
|
|
397
856
|
const seen = /* @__PURE__ */ new Set();
|
|
398
857
|
return locations.filter((loc) => {
|
|
@@ -406,100 +865,59 @@ var TypeScriptAdapter = class {
|
|
|
406
865
|
var typescriptAdapter = new TypeScriptAdapter();
|
|
407
866
|
|
|
408
867
|
// src/tools/resolve-definition.ts
|
|
409
|
-
async function resolveDefinition(symbol,
|
|
410
|
-
return await typescriptAdapter.resolveDefinition(symbol,
|
|
868
|
+
async function resolveDefinition(symbol, path5) {
|
|
869
|
+
return await typescriptAdapter.resolveDefinition(symbol, path5);
|
|
411
870
|
}
|
|
412
871
|
|
|
413
872
|
// src/tools/find-references.ts
|
|
414
|
-
|
|
415
|
-
|
|
873
|
+
init_cjs_shims();
|
|
874
|
+
async function findReferences(symbol, path5, limit = 50, offset = 0) {
|
|
875
|
+
return await typescriptAdapter.findReferences(symbol, path5, limit, offset);
|
|
416
876
|
}
|
|
417
877
|
|
|
418
878
|
// src/tools/find-implementations.ts
|
|
419
|
-
|
|
879
|
+
init_cjs_shims();
|
|
880
|
+
async function findImplementations(symbol, path5, limit = 50, offset = 0) {
|
|
420
881
|
return await typescriptAdapter.findImplementations(
|
|
421
882
|
symbol,
|
|
422
|
-
|
|
883
|
+
path5,
|
|
423
884
|
limit,
|
|
424
885
|
offset
|
|
425
886
|
);
|
|
426
887
|
}
|
|
427
888
|
|
|
428
889
|
// src/tools/get-file-structure.ts
|
|
890
|
+
init_cjs_shims();
|
|
429
891
|
async function getFileStructure(file) {
|
|
430
892
|
return await typescriptAdapter.getFileStructure(file);
|
|
431
893
|
}
|
|
432
894
|
|
|
433
|
-
// src/
|
|
434
|
-
|
|
435
|
-
var import_util = require("util");
|
|
436
|
-
var import_ripgrep = require("@vscode/ripgrep");
|
|
437
|
-
var execFileAsync = (0, import_util.promisify)(import_child_process.execFile);
|
|
438
|
-
async function searchCode(pattern, searchPath, filePattern, limit = 50) {
|
|
439
|
-
const args = [
|
|
440
|
-
"--json",
|
|
441
|
-
"--max-count",
|
|
442
|
-
limit.toString(),
|
|
443
|
-
"--fixed-strings",
|
|
444
|
-
// Default to fixed strings unless we want regex
|
|
445
|
-
pattern,
|
|
446
|
-
searchPath
|
|
447
|
-
];
|
|
448
|
-
if (filePattern) {
|
|
449
|
-
args.push("--glob", filePattern);
|
|
450
|
-
}
|
|
451
|
-
args.push("--glob", "!**/node_modules/**");
|
|
452
|
-
args.push("--glob", "!**/dist/**");
|
|
453
|
-
args.push("--glob", "!**/.git/**");
|
|
454
|
-
try {
|
|
455
|
-
const { stdout } = await execFileAsync(import_ripgrep.rgPath, args);
|
|
456
|
-
const lines = stdout.split("\n").filter(Boolean);
|
|
457
|
-
const results = [];
|
|
458
|
-
for (const line of lines) {
|
|
459
|
-
const data = JSON.parse(line);
|
|
460
|
-
if (data.type === "match") {
|
|
461
|
-
const file = data.data.path.text;
|
|
462
|
-
const lineNumber = data.data.line_number;
|
|
463
|
-
const submatches = data.data.submatches;
|
|
464
|
-
for (const submatch of submatches) {
|
|
465
|
-
results.push({
|
|
466
|
-
file,
|
|
467
|
-
line: lineNumber,
|
|
468
|
-
column: submatch.start,
|
|
469
|
-
text: data.data.lines.text.trim()
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
return results.slice(0, limit);
|
|
475
|
-
} catch (error) {
|
|
476
|
-
if (error.code === 1) {
|
|
477
|
-
return [];
|
|
478
|
-
}
|
|
479
|
-
throw error;
|
|
480
|
-
}
|
|
481
|
-
}
|
|
895
|
+
// src/index.ts
|
|
896
|
+
init_search_code();
|
|
482
897
|
|
|
483
898
|
// src/tools/get-symbol-docs.ts
|
|
484
|
-
|
|
899
|
+
init_cjs_shims();
|
|
900
|
+
var import_ts_morph4 = require("ts-morph");
|
|
901
|
+
init_security();
|
|
485
902
|
async function getSymbolDocs(symbol, filePath) {
|
|
486
|
-
const
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
903
|
+
const safePath = validateWorkspacePath(filePath);
|
|
904
|
+
const tsconfig = await projectManager.findNearestTsConfig(safePath);
|
|
905
|
+
if (!tsconfig) return void 0;
|
|
906
|
+
const project = projectManager.ensureProject(tsconfig);
|
|
907
|
+
const sourceFile = project.addSourceFileAtPathIfExists(safePath);
|
|
908
|
+
if (sourceFile) {
|
|
909
|
+
const node = sourceFile.getDescendantsOfKind(import_ts_morph4.SyntaxKind.Identifier).find((id) => id.getText() === symbol);
|
|
910
|
+
if (node) {
|
|
911
|
+
const decls = node.getSymbol()?.getDeclarations();
|
|
912
|
+
if (decls && decls.length > 0) {
|
|
913
|
+
const docs = typescriptAdapter.getSymbolDocs(decls[0]);
|
|
914
|
+
if (docs) {
|
|
915
|
+
return {
|
|
916
|
+
symbol,
|
|
917
|
+
file: sourceFile.getFilePath(),
|
|
918
|
+
line: sourceFile.getLineAndColumnAtPos(decls[0].getStart()).line,
|
|
919
|
+
...docs
|
|
920
|
+
};
|
|
503
921
|
}
|
|
504
922
|
}
|
|
505
923
|
}
|
|
@@ -507,49 +925,10 @@ async function getSymbolDocs(symbol, filePath) {
|
|
|
507
925
|
return void 0;
|
|
508
926
|
}
|
|
509
927
|
|
|
510
|
-
// src/index/symbol-index.ts
|
|
511
|
-
var SymbolIndex = class {
|
|
512
|
-
/**
|
|
513
|
-
* Build/Warm the index for a given path
|
|
514
|
-
*/
|
|
515
|
-
async buildIndex(rootDir) {
|
|
516
|
-
const startTime = Date.now();
|
|
517
|
-
const projects = await projectManager.getProjectsForPath(rootDir);
|
|
518
|
-
let fileCount = 0;
|
|
519
|
-
let functionCount = 0;
|
|
520
|
-
let classCount = 0;
|
|
521
|
-
let interfaceCount = 0;
|
|
522
|
-
let typeCount = 0;
|
|
523
|
-
for (const project of projects) {
|
|
524
|
-
const sourceFiles = project.getSourceFiles();
|
|
525
|
-
fileCount += sourceFiles.length;
|
|
526
|
-
for (const sourceFile of sourceFiles) {
|
|
527
|
-
functionCount += sourceFile.getFunctions().length;
|
|
528
|
-
classCount += sourceFile.getClasses().length;
|
|
529
|
-
interfaceCount += sourceFile.getInterfaces().length;
|
|
530
|
-
typeCount += sourceFile.getTypeAliases().length;
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
const duration = Date.now() - startTime;
|
|
534
|
-
const memoryUsage = process.memoryUsage().heapUsed / 1024 / 1024;
|
|
535
|
-
return {
|
|
536
|
-
indexed: {
|
|
537
|
-
files: fileCount,
|
|
538
|
-
functions: functionCount,
|
|
539
|
-
classes: classCount,
|
|
540
|
-
interfaces: interfaceCount,
|
|
541
|
-
types: typeCount
|
|
542
|
-
},
|
|
543
|
-
duration_ms: duration,
|
|
544
|
-
memory_mb: Math.round(memoryUsage)
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
};
|
|
548
|
-
var symbolIndex = new SymbolIndex();
|
|
549
|
-
|
|
550
928
|
// src/tools/build-symbol-index.ts
|
|
551
|
-
|
|
552
|
-
|
|
929
|
+
init_cjs_shims();
|
|
930
|
+
async function buildSymbolIndex(path5) {
|
|
931
|
+
return await symbolIndex.buildIndex(path5);
|
|
553
932
|
}
|
|
554
933
|
|
|
555
934
|
// src/index.ts
|
|
@@ -643,7 +1022,8 @@ var ASTExplorerServer = class {
|
|
|
643
1022
|
pattern: { type: "string", description: "Search pattern" },
|
|
644
1023
|
path: { type: "string", description: "Directory to search" },
|
|
645
1024
|
filePattern: { type: "string", description: "Glob filter" },
|
|
646
|
-
limit: { type: "number", default: 50 }
|
|
1025
|
+
limit: { type: "number", default: 50 },
|
|
1026
|
+
regex: { type: "boolean", default: true }
|
|
647
1027
|
},
|
|
648
1028
|
required: ["pattern", "path"]
|
|
649
1029
|
}
|
|
@@ -679,8 +1059,8 @@ var ASTExplorerServer = class {
|
|
|
679
1059
|
try {
|
|
680
1060
|
switch (name) {
|
|
681
1061
|
case "resolve_definition": {
|
|
682
|
-
const { symbol, path:
|
|
683
|
-
const results = await resolveDefinition(symbol,
|
|
1062
|
+
const { symbol, path: path5 } = ResolveDefinitionSchema.parse(args);
|
|
1063
|
+
const results = await resolveDefinition(symbol, path5);
|
|
684
1064
|
return {
|
|
685
1065
|
content: [
|
|
686
1066
|
{ type: "text", text: JSON.stringify(results, null, 2) }
|
|
@@ -688,8 +1068,8 @@ var ASTExplorerServer = class {
|
|
|
688
1068
|
};
|
|
689
1069
|
}
|
|
690
1070
|
case "find_references": {
|
|
691
|
-
const { symbol, path:
|
|
692
|
-
const results = await findReferences(symbol,
|
|
1071
|
+
const { symbol, path: path5, limit, offset } = FindReferencesSchema.parse(args);
|
|
1072
|
+
const results = await findReferences(symbol, path5, limit, offset);
|
|
693
1073
|
return {
|
|
694
1074
|
content: [
|
|
695
1075
|
{ type: "text", text: JSON.stringify(results, null, 2) }
|
|
@@ -697,10 +1077,10 @@ var ASTExplorerServer = class {
|
|
|
697
1077
|
};
|
|
698
1078
|
}
|
|
699
1079
|
case "find_implementations": {
|
|
700
|
-
const { symbol, path:
|
|
1080
|
+
const { symbol, path: path5, limit, offset } = FindImplementationsSchema.parse(args);
|
|
701
1081
|
const results = await findImplementations(
|
|
702
1082
|
symbol,
|
|
703
|
-
|
|
1083
|
+
path5,
|
|
704
1084
|
limit,
|
|
705
1085
|
offset
|
|
706
1086
|
);
|
|
@@ -720,8 +1100,14 @@ var ASTExplorerServer = class {
|
|
|
720
1100
|
};
|
|
721
1101
|
}
|
|
722
1102
|
case "search_code": {
|
|
723
|
-
const { pattern, path:
|
|
724
|
-
const results = await searchCode(
|
|
1103
|
+
const { pattern, path: path5, filePattern, limit, regex } = SearchCodeSchema.parse(args);
|
|
1104
|
+
const results = await searchCode(
|
|
1105
|
+
pattern,
|
|
1106
|
+
path5,
|
|
1107
|
+
filePattern,
|
|
1108
|
+
limit,
|
|
1109
|
+
regex
|
|
1110
|
+
);
|
|
725
1111
|
return {
|
|
726
1112
|
content: [
|
|
727
1113
|
{ type: "text", text: JSON.stringify(results, null, 2) }
|
|
@@ -729,15 +1115,15 @@ var ASTExplorerServer = class {
|
|
|
729
1115
|
};
|
|
730
1116
|
}
|
|
731
1117
|
case "get_symbol_docs": {
|
|
732
|
-
const { symbol, path:
|
|
733
|
-
const docs = await getSymbolDocs(symbol,
|
|
1118
|
+
const { symbol, path: path5 } = GetSymbolDocsSchema.parse(args);
|
|
1119
|
+
const docs = await getSymbolDocs(symbol, path5);
|
|
734
1120
|
return {
|
|
735
1121
|
content: [{ type: "text", text: JSON.stringify(docs, null, 2) }]
|
|
736
1122
|
};
|
|
737
1123
|
}
|
|
738
1124
|
case "build_symbol_index": {
|
|
739
|
-
const { path:
|
|
740
|
-
const stats = await buildSymbolIndex(
|
|
1125
|
+
const { path: path5 } = BuildSymbolIndexSchema.parse(args);
|
|
1126
|
+
const stats = await buildSymbolIndex(path5);
|
|
741
1127
|
return {
|
|
742
1128
|
content: [{ type: "text", text: JSON.stringify(stats, null, 2) }]
|
|
743
1129
|
};
|