@yuaone/core 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-loop.d.ts +15 -27
- package/dist/agent-loop.d.ts.map +1 -1
- package/dist/agent-loop.js +319 -28
- package/dist/agent-loop.js.map +1 -1
- package/dist/ast-analyzer.d.ts +147 -0
- package/dist/ast-analyzer.d.ts.map +1 -0
- package/dist/ast-analyzer.js +344 -0
- package/dist/ast-analyzer.js.map +1 -0
- package/dist/codebase-context.d.ts +24 -4
- package/dist/codebase-context.d.ts.map +1 -1
- package/dist/codebase-context.js +100 -10
- package/dist/codebase-context.js.map +1 -1
- package/dist/constants.d.ts +7 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +7 -0
- package/dist/constants.js.map +1 -1
- package/dist/cross-file-refactor.d.ts +12 -3
- package/dist/cross-file-refactor.d.ts.map +1 -1
- package/dist/cross-file-refactor.js +35 -3
- package/dist/cross-file-refactor.js.map +1 -1
- package/dist/execution-engine.d.ts +9 -0
- package/dist/execution-engine.d.ts.map +1 -1
- package/dist/execution-engine.js +59 -10
- package/dist/execution-engine.js.map +1 -1
- package/dist/index.d.ts +4 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -11
- package/dist/index.js.map +1 -1
- package/dist/security.d.ts.map +1 -1
- package/dist/security.js +15 -8
- package/dist/security.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/vector-store.d.ts +148 -0
- package/dist/vector-store.d.ts.map +1 -0
- package/dist/vector-store.js +328 -0
- package/dist/vector-store.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module ast-analyzer
|
|
3
|
+
* @description AST-based TypeScript/JavaScript code analysis using ts-morph.
|
|
4
|
+
*
|
|
5
|
+
* Provides accurate symbol extraction, import analysis, and reference finding
|
|
6
|
+
* that avoids regex false positives (symbols in comments/strings, type-only imports, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Falls back gracefully when ts-morph cannot load the project (e.g., missing tsconfig).
|
|
9
|
+
*/
|
|
10
|
+
import { resolve, dirname } from "node:path";
|
|
11
|
+
import { existsSync } from "node:fs";
|
|
12
|
+
let TsMorphCtor = null;
|
|
13
|
+
let tsMorphLoadAttempted = false;
|
|
14
|
+
async function loadTsMorph() {
|
|
15
|
+
if (tsMorphLoadAttempted)
|
|
16
|
+
return TsMorphCtor ? { Project: TsMorphCtor } : null;
|
|
17
|
+
tsMorphLoadAttempted = true;
|
|
18
|
+
try {
|
|
19
|
+
const mod = await import("ts-morph");
|
|
20
|
+
TsMorphCtor = mod.Project;
|
|
21
|
+
return mod;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// ─── AstAnalyzer ───
|
|
28
|
+
/**
|
|
29
|
+
* AST-based code analysis for TypeScript/JavaScript files.
|
|
30
|
+
*
|
|
31
|
+
* Uses ts-morph for accurate parsing — avoids regex false positives for symbols
|
|
32
|
+
* in comments/strings, correctly detects type-only imports, and finds precise
|
|
33
|
+
* symbol references.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* const analyzer = new AstAnalyzer("/path/to/project");
|
|
38
|
+
* const symbols = await analyzer.extractSymbols("/path/to/file.ts");
|
|
39
|
+
* const refs = await analyzer.findReferences("/path/to/file.ts", "MyClass");
|
|
40
|
+
* const imports = await analyzer.getImports("/path/to/file.ts");
|
|
41
|
+
* const isType = await analyzer.isTypeOnlyImport("/path/to/file.ts", "Foo");
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export class AstAnalyzer {
|
|
45
|
+
projectPath;
|
|
46
|
+
/** Cached ts-morph Project instances keyed by tsconfig path */
|
|
47
|
+
projects = new Map();
|
|
48
|
+
constructor(projectPath) {
|
|
49
|
+
this.projectPath = resolve(projectPath);
|
|
50
|
+
}
|
|
51
|
+
// ─── Public API ───
|
|
52
|
+
/**
|
|
53
|
+
* Extract all exported symbols from a TypeScript/JavaScript file using AST.
|
|
54
|
+
*
|
|
55
|
+
* Returns functions, classes, interfaces, types, enums, and variables that
|
|
56
|
+
* are exported. Includes accurate line numbers from the AST (not regex estimates).
|
|
57
|
+
*
|
|
58
|
+
* @param filePath - Absolute or project-relative path to the file
|
|
59
|
+
* @returns Array of exported symbols, or empty array on failure
|
|
60
|
+
*/
|
|
61
|
+
async extractSymbols(filePath) {
|
|
62
|
+
const absPath = resolve(filePath);
|
|
63
|
+
try {
|
|
64
|
+
const sf = await this.getSourceFile(absPath);
|
|
65
|
+
if (!sf)
|
|
66
|
+
return [];
|
|
67
|
+
return this.extractSymbolsFromSourceFile(sf, absPath);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Find all references to a named symbol across the project files.
|
|
75
|
+
*
|
|
76
|
+
* Uses ts-morph's language-service-level reference finder — accurate even for
|
|
77
|
+
* overloaded names, avoids matches inside comments or string literals.
|
|
78
|
+
*
|
|
79
|
+
* @param filePath - File where the symbol is defined
|
|
80
|
+
* @param symbolName - Name of the symbol to find references for
|
|
81
|
+
* @returns Array of references with file path, line, and source context
|
|
82
|
+
*/
|
|
83
|
+
async findReferences(filePath, symbolName) {
|
|
84
|
+
const absPath = resolve(filePath);
|
|
85
|
+
try {
|
|
86
|
+
const sf = await this.getSourceFile(absPath);
|
|
87
|
+
if (!sf)
|
|
88
|
+
return [];
|
|
89
|
+
const results = [];
|
|
90
|
+
// Find the declaration node for the symbol in this file
|
|
91
|
+
const declarations = sf.getExportedDeclarations().get(symbolName) ?? [];
|
|
92
|
+
for (const decl of declarations) {
|
|
93
|
+
// SourceFile is in the ExportedDeclarations union but lacks findReferencesAsNodes
|
|
94
|
+
if (!("findReferencesAsNodes" in decl))
|
|
95
|
+
continue;
|
|
96
|
+
const refs = decl.findReferencesAsNodes();
|
|
97
|
+
for (const ref of refs) {
|
|
98
|
+
const refSf = ref.getSourceFile();
|
|
99
|
+
const refFilePath = refSf.getFilePath();
|
|
100
|
+
const line = ref.getStartLineNumber();
|
|
101
|
+
const lineText = refSf.getFullText().split("\n")[line - 1] ?? "";
|
|
102
|
+
results.push({
|
|
103
|
+
file: refFilePath,
|
|
104
|
+
line,
|
|
105
|
+
context: lineText,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return results;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Parse all import statements in a file via AST.
|
|
117
|
+
*
|
|
118
|
+
* Correctly identifies type-only imports (both `import type { X }` and
|
|
119
|
+
* `import { type X, Y }`).
|
|
120
|
+
*
|
|
121
|
+
* @param filePath - Absolute or project-relative path to the file
|
|
122
|
+
* @returns Array of parsed import information, or empty array on failure
|
|
123
|
+
*/
|
|
124
|
+
async getImports(filePath) {
|
|
125
|
+
const absPath = resolve(filePath);
|
|
126
|
+
try {
|
|
127
|
+
const sf = await this.getSourceFile(absPath);
|
|
128
|
+
if (!sf)
|
|
129
|
+
return [];
|
|
130
|
+
return this.extractImportsFromSourceFile(sf);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check whether a specific imported name is type-only in a file.
|
|
138
|
+
*
|
|
139
|
+
* Returns true if:
|
|
140
|
+
* - The entire import clause is `import type { X }`, or
|
|
141
|
+
* - The specific named import is `import { type X, Y }` (TS 4.5+ inline type modifier)
|
|
142
|
+
*
|
|
143
|
+
* @param filePath - Absolute or project-relative path to the file
|
|
144
|
+
* @param importedName - The name to check (e.g., "Foo")
|
|
145
|
+
* @returns true if the import is type-only, false otherwise
|
|
146
|
+
*/
|
|
147
|
+
async isTypeOnlyImport(filePath, importedName) {
|
|
148
|
+
try {
|
|
149
|
+
const imports = await this.getImports(filePath);
|
|
150
|
+
for (const imp of imports) {
|
|
151
|
+
// Full clause type-only: import type { X, Y } from "…"
|
|
152
|
+
if (imp.isTypeOnly && imp.namedImports.includes(importedName))
|
|
153
|
+
return true;
|
|
154
|
+
// Inline type modifier: import { type X, Y } from "…"
|
|
155
|
+
if (imp.typeOnlyNames.includes(importedName))
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// ─── Internal helpers ───
|
|
165
|
+
/**
|
|
166
|
+
* Get or create a ts-morph Project for the file's tsconfig.
|
|
167
|
+
* Falls back to a ts-morph Project with no tsconfig if one cannot be found.
|
|
168
|
+
*/
|
|
169
|
+
async getProject(absFilePath) {
|
|
170
|
+
const mod = await loadTsMorph();
|
|
171
|
+
if (!mod)
|
|
172
|
+
return null;
|
|
173
|
+
const tsConfigPath = this.findTsConfig(absFilePath);
|
|
174
|
+
const cacheKey = tsConfigPath ?? "__no_tsconfig__";
|
|
175
|
+
if (this.projects.has(cacheKey)) {
|
|
176
|
+
return this.projects.get(cacheKey);
|
|
177
|
+
}
|
|
178
|
+
try {
|
|
179
|
+
let project;
|
|
180
|
+
if (tsConfigPath) {
|
|
181
|
+
project = new mod.Project({
|
|
182
|
+
tsConfigFilePath: tsConfigPath,
|
|
183
|
+
skipAddingFilesFromTsConfig: false,
|
|
184
|
+
skipFileDependencyResolution: false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
// No tsconfig found — use defaults so we can still parse individual files
|
|
189
|
+
project = new mod.Project({
|
|
190
|
+
useInMemoryFileSystem: false,
|
|
191
|
+
skipAddingFilesFromTsConfig: true,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
this.projects.set(cacheKey, project);
|
|
195
|
+
return project;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// Construction failed (e.g., invalid tsconfig)
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Get a ts-morph SourceFile for the given absolute path.
|
|
204
|
+
* Adds the file to the project if it's not already tracked.
|
|
205
|
+
*/
|
|
206
|
+
async getSourceFile(absFilePath) {
|
|
207
|
+
const project = await this.getProject(absFilePath);
|
|
208
|
+
if (!project)
|
|
209
|
+
return null;
|
|
210
|
+
// Try to get from already-loaded files
|
|
211
|
+
let sf = project.getSourceFile(absFilePath);
|
|
212
|
+
if (!sf) {
|
|
213
|
+
try {
|
|
214
|
+
sf = project.addSourceFileAtPath(absFilePath);
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return sf ?? null;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Walk up from the file's directory to find the nearest tsconfig.json.
|
|
224
|
+
* Stops at the project root.
|
|
225
|
+
*/
|
|
226
|
+
findTsConfig(absFilePath) {
|
|
227
|
+
let dir = dirname(absFilePath);
|
|
228
|
+
const root = this.projectPath;
|
|
229
|
+
// Walk up directory tree until we reach the project root (or filesystem root)
|
|
230
|
+
while (dir.length >= root.length) {
|
|
231
|
+
const candidate = `${dir}/tsconfig.json`;
|
|
232
|
+
if (existsSync(candidate))
|
|
233
|
+
return candidate;
|
|
234
|
+
const parent = dirname(dir);
|
|
235
|
+
if (parent === dir)
|
|
236
|
+
break; // filesystem root
|
|
237
|
+
dir = parent;
|
|
238
|
+
}
|
|
239
|
+
// Also check project root tsconfig as last resort
|
|
240
|
+
const projectTsConfig = `${root}/tsconfig.json`;
|
|
241
|
+
if (existsSync(projectTsConfig))
|
|
242
|
+
return projectTsConfig;
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Extract exported symbols from a ts-morph SourceFile.
|
|
247
|
+
*/
|
|
248
|
+
extractSymbolsFromSourceFile(sf, filePath) {
|
|
249
|
+
const symbols = [];
|
|
250
|
+
// ts-morph getExportedDeclarations() returns a ReadonlyMap<string, ExportedDeclarations[]>
|
|
251
|
+
const exportedDecls = sf.getExportedDeclarations();
|
|
252
|
+
const defaultName = "__default__";
|
|
253
|
+
for (const [name, decls] of exportedDecls) {
|
|
254
|
+
const isDefault = name === "default";
|
|
255
|
+
const symbolName = isDefault ? defaultName : name;
|
|
256
|
+
for (const decl of decls) {
|
|
257
|
+
const kind = this.mapDeclarationKind(decl);
|
|
258
|
+
if (!kind)
|
|
259
|
+
continue;
|
|
260
|
+
const startLine = decl.getStartLineNumber(true);
|
|
261
|
+
const endLine = decl.getEndLineNumber();
|
|
262
|
+
symbols.push({
|
|
263
|
+
name: isDefault ? symbolName : name,
|
|
264
|
+
kind,
|
|
265
|
+
line: startLine,
|
|
266
|
+
endLine,
|
|
267
|
+
isDefault,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
return symbols;
|
|
272
|
+
}
|
|
273
|
+
/**
|
|
274
|
+
* Map a ts-morph Node to our AstSymbol kind string.
|
|
275
|
+
* Returns undefined for node kinds we don't track.
|
|
276
|
+
*/
|
|
277
|
+
mapDeclarationKind(decl) {
|
|
278
|
+
// Use ts-morph's SyntaxKind checks via getKindName()
|
|
279
|
+
const kindName = decl.getKindName();
|
|
280
|
+
if (kindName === "FunctionDeclaration" ||
|
|
281
|
+
kindName === "ArrowFunction" ||
|
|
282
|
+
kindName === "FunctionExpression") {
|
|
283
|
+
return "function";
|
|
284
|
+
}
|
|
285
|
+
if (kindName === "ClassDeclaration" || kindName === "ClassExpression") {
|
|
286
|
+
return "class";
|
|
287
|
+
}
|
|
288
|
+
if (kindName === "InterfaceDeclaration") {
|
|
289
|
+
return "interface";
|
|
290
|
+
}
|
|
291
|
+
if (kindName === "TypeAliasDeclaration") {
|
|
292
|
+
return "type";
|
|
293
|
+
}
|
|
294
|
+
if (kindName === "EnumDeclaration") {
|
|
295
|
+
return "enum";
|
|
296
|
+
}
|
|
297
|
+
if (kindName === "VariableDeclaration" ||
|
|
298
|
+
kindName === "VariableStatement") {
|
|
299
|
+
return "variable";
|
|
300
|
+
}
|
|
301
|
+
return undefined;
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Extract import information from a ts-morph SourceFile.
|
|
305
|
+
*/
|
|
306
|
+
extractImportsFromSourceFile(sf) {
|
|
307
|
+
const imports = [];
|
|
308
|
+
for (const importDecl of sf.getImportDeclarations()) {
|
|
309
|
+
const moduleSpecifier = importDecl.getModuleSpecifierValue();
|
|
310
|
+
const isTypeOnly = importDecl.isTypeOnly();
|
|
311
|
+
const line = importDecl.getStartLineNumber(true);
|
|
312
|
+
const namedImports = [];
|
|
313
|
+
const typeOnlyNames = [];
|
|
314
|
+
for (const named of importDecl.getNamedImports()) {
|
|
315
|
+
const nm = named.getName();
|
|
316
|
+
namedImports.push(nm);
|
|
317
|
+
// TS 4.5+: `import { type X, Y }` — individual type modifier
|
|
318
|
+
if (named.isTypeOnly()) {
|
|
319
|
+
typeOnlyNames.push(nm);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const defaultImportNode = importDecl.getDefaultImport();
|
|
323
|
+
const namespaceImportNode = importDecl.getNamespaceImport();
|
|
324
|
+
imports.push({
|
|
325
|
+
moduleSpecifier,
|
|
326
|
+
namedImports,
|
|
327
|
+
defaultImport: defaultImportNode?.getText(),
|
|
328
|
+
namespaceImport: namespaceImportNode?.getText(),
|
|
329
|
+
isTypeOnly,
|
|
330
|
+
typeOnlyNames,
|
|
331
|
+
line,
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
return imports;
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Dispose all cached ts-morph Project instances to free memory.
|
|
338
|
+
* Call this when analysis is complete.
|
|
339
|
+
*/
|
|
340
|
+
dispose() {
|
|
341
|
+
this.projects.clear();
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=ast-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast-analyzer.js","sourceRoot":"","sources":["../src/ast-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* @description Codebase Context Engine — indexes TypeScript/JavaScript projects,
|
|
4
4
|
* extracts symbols, builds call graphs, and provides semantic search + blast radius analysis.
|
|
5
5
|
*
|
|
6
|
-
* Uses regex-based
|
|
7
|
-
*
|
|
6
|
+
* Uses regex-based parsing with an optional ts-morph AST layer for improved accuracy on
|
|
7
|
+
* TypeScript/JavaScript files (avoids false positives in comments/strings, correctly detects
|
|
8
|
+
* type-only imports). Falls back to regex when ts-morph is unavailable.
|
|
8
9
|
*/
|
|
9
10
|
import type { ImportRef } from "./dependency-analyzer.js";
|
|
10
11
|
import { LanguageSupport } from "./language-support.js";
|
|
@@ -172,6 +173,8 @@ export declare class CodebaseContext {
|
|
|
172
173
|
private reverseDepMap;
|
|
173
174
|
/** Optional multi-language support for non-TS/JS files */
|
|
174
175
|
private languageSupport;
|
|
176
|
+
/** AST-based analyzer for accurate TS/JS analysis (ts-morph) */
|
|
177
|
+
private astAnalyzer;
|
|
175
178
|
constructor(projectPath: string, languageSupport?: LanguageSupport);
|
|
176
179
|
/**
|
|
177
180
|
* Build a full index of the project. Scans all source files,
|
|
@@ -343,10 +346,27 @@ export declare class CodebaseContext {
|
|
|
343
346
|
* Analyze a single source file — extract symbols, imports, exports,
|
|
344
347
|
* and compute complexity metrics.
|
|
345
348
|
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
349
|
+
* For TypeScript/JavaScript files, first attempts AST-based extraction via AstAnalyzer
|
|
350
|
+
* (ts-morph) for improved accuracy, then merges/falls back to regex-based extraction.
|
|
351
|
+
* When LanguageSupport is available and the file is not TS/JS, uses language-specific
|
|
352
|
+
* patterns for symbol extraction.
|
|
348
353
|
*/
|
|
349
354
|
private analyzeFile;
|
|
355
|
+
/**
|
|
356
|
+
* Try AST-based symbol extraction (ts-morph) for a TS/JS file.
|
|
357
|
+
* If AstAnalyzer returns results, merges them with regex results to fill in detail
|
|
358
|
+
* (params, jsdoc, etc.) not available from the AST layer alone.
|
|
359
|
+
* Falls back to pure regex extraction on any error or empty AST result.
|
|
360
|
+
*/
|
|
361
|
+
private extractSymbolsWithAstFallback;
|
|
362
|
+
/**
|
|
363
|
+
* Merge AST symbol info (accurate line numbers, exported status) with regex symbol info
|
|
364
|
+
* (params, jsdoc, return types). AST results are authoritative for line/endLine/exported/isDefault.
|
|
365
|
+
* Symbols found by AST but not regex are included as minimal entries (no params/jsdoc).
|
|
366
|
+
* Symbols found by regex but not AST are included as-is (regex may have false positives
|
|
367
|
+
* for unexported symbols inside bodies, which is acceptable).
|
|
368
|
+
*/
|
|
369
|
+
private mergeAstAndRegexSymbols;
|
|
350
370
|
/**
|
|
351
371
|
* Extract all symbol definitions from file content using regex patterns.
|
|
352
372
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codebase-context.d.ts","sourceRoot":"","sources":["../src/codebase-context.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"codebase-context.d.ts","sourceRoot":"","sources":["../src/codebase-context.ts"],"names":[],"mappings":"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"}
|
package/dist/codebase-context.js
CHANGED
|
@@ -3,11 +3,13 @@
|
|
|
3
3
|
* @description Codebase Context Engine — indexes TypeScript/JavaScript projects,
|
|
4
4
|
* extracts symbols, builds call graphs, and provides semantic search + blast radius analysis.
|
|
5
5
|
*
|
|
6
|
-
* Uses regex-based
|
|
7
|
-
*
|
|
6
|
+
* Uses regex-based parsing with an optional ts-morph AST layer for improved accuracy on
|
|
7
|
+
* TypeScript/JavaScript files (avoids false positives in comments/strings, correctly detects
|
|
8
|
+
* type-only imports). Falls back to regex when ts-morph is unavailable.
|
|
8
9
|
*/
|
|
9
10
|
import { readdir, readFile } from "node:fs/promises";
|
|
10
11
|
import { join, resolve, extname, relative } from "node:path";
|
|
12
|
+
import { AstAnalyzer } from "./ast-analyzer.js";
|
|
11
13
|
// ─── Constants ───
|
|
12
14
|
const SOURCE_EXTENSIONS = new Set([".ts", ".tsx", ".js", ".jsx"]);
|
|
13
15
|
const SKIP_DIRS = new Set([
|
|
@@ -69,9 +71,12 @@ export class CodebaseContext {
|
|
|
69
71
|
reverseDepMap = new Map();
|
|
70
72
|
/** Optional multi-language support for non-TS/JS files */
|
|
71
73
|
languageSupport;
|
|
74
|
+
/** AST-based analyzer for accurate TS/JS analysis (ts-morph) */
|
|
75
|
+
astAnalyzer;
|
|
72
76
|
constructor(projectPath, languageSupport) {
|
|
73
77
|
this.projectPath = resolve(projectPath);
|
|
74
78
|
this.languageSupport = languageSupport ?? null;
|
|
79
|
+
this.astAnalyzer = new AstAnalyzer(this.projectPath);
|
|
75
80
|
this.index = {
|
|
76
81
|
files: new Map(),
|
|
77
82
|
symbolTable: new Map(),
|
|
@@ -100,7 +105,7 @@ export class CodebaseContext {
|
|
|
100
105
|
try {
|
|
101
106
|
const content = await readFile(filePath, "utf-8");
|
|
102
107
|
this.fileContents.set(filePath, content);
|
|
103
|
-
const analysis = this.analyzeFile(filePath, content);
|
|
108
|
+
const analysis = await this.analyzeFile(filePath, content);
|
|
104
109
|
this.index.files.set(filePath, analysis);
|
|
105
110
|
}
|
|
106
111
|
catch {
|
|
@@ -128,7 +133,7 @@ export class CodebaseContext {
|
|
|
128
133
|
try {
|
|
129
134
|
const content = await readFile(absPath, "utf-8");
|
|
130
135
|
this.fileContents.set(absPath, content);
|
|
131
|
-
const analysis = this.analyzeFile(absPath, content);
|
|
136
|
+
const analysis = await this.analyzeFile(absPath, content);
|
|
132
137
|
this.index.files.set(absPath, analysis);
|
|
133
138
|
}
|
|
134
139
|
catch {
|
|
@@ -644,10 +649,12 @@ export class CodebaseContext {
|
|
|
644
649
|
* Analyze a single source file — extract symbols, imports, exports,
|
|
645
650
|
* and compute complexity metrics.
|
|
646
651
|
*
|
|
647
|
-
*
|
|
648
|
-
*
|
|
652
|
+
* For TypeScript/JavaScript files, first attempts AST-based extraction via AstAnalyzer
|
|
653
|
+
* (ts-morph) for improved accuracy, then merges/falls back to regex-based extraction.
|
|
654
|
+
* When LanguageSupport is available and the file is not TS/JS, uses language-specific
|
|
655
|
+
* patterns for symbol extraction.
|
|
649
656
|
*/
|
|
650
|
-
analyzeFile(filePath, content) {
|
|
657
|
+
async analyzeFile(filePath, content) {
|
|
651
658
|
const ext = extname(filePath);
|
|
652
659
|
const isTsJs = ext === ".ts" || ext === ".tsx" || ext === ".js" || ext === ".jsx";
|
|
653
660
|
// Detect language — use LanguageSupport when available, fallback to TS/JS
|
|
@@ -662,13 +669,13 @@ export class CodebaseContext {
|
|
|
662
669
|
language = "javascript"; // shouldn't happen, but safe fallback
|
|
663
670
|
}
|
|
664
671
|
const lines = content.split("\n");
|
|
665
|
-
// For TS/JS files or when LanguageSupport is unavailable, use built-in extraction
|
|
666
|
-
// For other languages, use LanguageSupport patterns for basic symbol extraction
|
|
667
672
|
let symbols;
|
|
668
673
|
if (isTsJs || !this.languageSupport) {
|
|
669
|
-
|
|
674
|
+
// For TS/JS: try AST-based extraction first for accuracy, fall back to regex
|
|
675
|
+
symbols = await this.extractSymbolsWithAstFallback(filePath, content, lines);
|
|
670
676
|
}
|
|
671
677
|
else {
|
|
678
|
+
// For other languages: use LanguageSupport patterns
|
|
672
679
|
symbols = this.extractSymbolsWithLanguageSupport(filePath, content, lines, language);
|
|
673
680
|
}
|
|
674
681
|
const imports = this.extractImports(content);
|
|
@@ -677,6 +684,89 @@ export class CodebaseContext {
|
|
|
677
684
|
const complexity = this.computeComplexity(content, lines, imports.length);
|
|
678
685
|
return { file: filePath, language, symbols, imports, exports, callEdges, complexity };
|
|
679
686
|
}
|
|
687
|
+
/**
|
|
688
|
+
* Try AST-based symbol extraction (ts-morph) for a TS/JS file.
|
|
689
|
+
* If AstAnalyzer returns results, merges them with regex results to fill in detail
|
|
690
|
+
* (params, jsdoc, etc.) not available from the AST layer alone.
|
|
691
|
+
* Falls back to pure regex extraction on any error or empty AST result.
|
|
692
|
+
*/
|
|
693
|
+
async extractSymbolsWithAstFallback(filePath, content, lines) {
|
|
694
|
+
try {
|
|
695
|
+
const astSymbols = await this.astAnalyzer.extractSymbols(filePath);
|
|
696
|
+
if (astSymbols.length > 0) {
|
|
697
|
+
// AstAnalyzer succeeded — use regex extraction to get full detail (params, jsdoc…),
|
|
698
|
+
// but trust AST line numbers and exported status for the symbols it found.
|
|
699
|
+
const regexSymbols = this.extractSymbols(filePath, content, lines);
|
|
700
|
+
return this.mergeAstAndRegexSymbols(astSymbols, regexSymbols, filePath);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
catch {
|
|
704
|
+
// AstAnalyzer failed — fall through to regex
|
|
705
|
+
}
|
|
706
|
+
return this.extractSymbols(filePath, content, lines);
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Merge AST symbol info (accurate line numbers, exported status) with regex symbol info
|
|
710
|
+
* (params, jsdoc, return types). AST results are authoritative for line/endLine/exported/isDefault.
|
|
711
|
+
* Symbols found by AST but not regex are included as minimal entries (no params/jsdoc).
|
|
712
|
+
* Symbols found by regex but not AST are included as-is (regex may have false positives
|
|
713
|
+
* for unexported symbols inside bodies, which is acceptable).
|
|
714
|
+
*/
|
|
715
|
+
mergeAstAndRegexSymbols(astSymbols, regexSymbols, filePath) {
|
|
716
|
+
const merged = [];
|
|
717
|
+
const regexByName = new Map();
|
|
718
|
+
for (const sym of regexSymbols) {
|
|
719
|
+
const arr = regexByName.get(sym.name) ?? [];
|
|
720
|
+
arr.push(sym);
|
|
721
|
+
regexByName.set(sym.name, arr);
|
|
722
|
+
}
|
|
723
|
+
const astNames = new Set();
|
|
724
|
+
for (const astSym of astSymbols) {
|
|
725
|
+
const displayName = astSym.isDefault && astSym.name === "__default__" ? "default" : astSym.name;
|
|
726
|
+
astNames.add(displayName);
|
|
727
|
+
// Find the best matching regex symbol (by name, pick closest line)
|
|
728
|
+
const candidates = regexByName.get(displayName) ?? [];
|
|
729
|
+
let best;
|
|
730
|
+
let bestLineDiff = Infinity;
|
|
731
|
+
for (const candidate of candidates) {
|
|
732
|
+
const diff = Math.abs(candidate.line - astSym.line);
|
|
733
|
+
if (diff < bestLineDiff) {
|
|
734
|
+
bestLineDiff = diff;
|
|
735
|
+
best = candidate;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
if (best && bestLineDiff <= 5) {
|
|
739
|
+
// Merge: use AST accuracy for line/endLine/exported/isDefault, regex for the rest
|
|
740
|
+
merged.push({
|
|
741
|
+
...best,
|
|
742
|
+
line: astSym.line,
|
|
743
|
+
endLine: astSym.endLine,
|
|
744
|
+
exported: true, // AST found it as exported declaration
|
|
745
|
+
isDefault: astSym.isDefault,
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
// AST found a symbol regex missed — include as a minimal entry
|
|
750
|
+
merged.push({
|
|
751
|
+
name: displayName,
|
|
752
|
+
kind: astSym.kind,
|
|
753
|
+
file: filePath,
|
|
754
|
+
line: astSym.line,
|
|
755
|
+
endLine: astSym.endLine,
|
|
756
|
+
exported: true,
|
|
757
|
+
isDefault: astSym.isDefault,
|
|
758
|
+
isAsync: false,
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
// Include regex-found symbols not covered by AST (unexported/internal — AST only returns exports)
|
|
763
|
+
for (const sym of regexSymbols) {
|
|
764
|
+
if (!astNames.has(sym.name)) {
|
|
765
|
+
merged.push(sym);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return merged;
|
|
769
|
+
}
|
|
680
770
|
/**
|
|
681
771
|
* Extract all symbol definitions from file content using regex patterns.
|
|
682
772
|
*/
|