@defai.digital/ax-cli 3.15.0 → 3.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -2
- package/dist/mcp/client-v2.js +4 -2
- package/dist/mcp/client-v2.js.map +1 -1
- package/dist/mcp/zai-templates.js +4 -0
- package/dist/mcp/zai-templates.js.map +1 -1
- package/dist/schemas/settings-schemas.js +4 -0
- package/dist/schemas/settings-schemas.js.map +1 -1
- package/package.json +1 -1
- package/.ax-cli/CUSTOM.md +0 -97
- package/.ax-cli/auto-accept-audit.json +0 -1302
- package/.ax-cli/index.json +0 -43
- package/.ax-cli/memory.json +0 -62
- package/.ax-cli/settings.json +0 -39
- package/ax.config.json +0 -304
- package/dist/analyzers/ast/tree-sitter-parser.d.ts +0 -134
- package/dist/analyzers/ast/tree-sitter-parser.js +0 -730
- package/dist/analyzers/ast/tree-sitter-parser.js.map +0 -1
- package/dist/mcp/config-detector-v2.d.ts +0 -83
- package/dist/mcp/config-detector-v2.js +0 -328
- package/dist/mcp/config-detector-v2.js.map +0 -1
- package/dist/mcp/config-migrator-v2.d.ts +0 -89
- package/dist/mcp/config-migrator-v2.js +0 -288
- package/dist/mcp/config-migrator-v2.js.map +0 -1
- package/dist/mcp/config-v2.d.ts +0 -111
- package/dist/mcp/config-v2.js +0 -443
- package/dist/mcp/config-v2.js.map +0 -1
- package/dist/mcp/transports-v2.d.ts +0 -152
- package/dist/mcp/transports-v2.js +0 -481
- package/dist/mcp/transports-v2.js.map +0 -1
- package/dist/utils/error-sanitizer.d.ts +0 -119
- package/dist/utils/error-sanitizer.js +0 -253
- package/dist/utils/error-sanitizer.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -74
- package/dist/utils/errors.js +0 -139
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/incremental-analyzer.d.ts +0 -134
- package/dist/utils/incremental-analyzer.js +0 -377
- package/dist/utils/incremental-analyzer.js.map +0 -1
- package/dist/utils/math.d.ts +0 -1
- package/dist/utils/math.js +0 -4
- package/dist/utils/math.js.map +0 -1
- package/dist/utils/settings.d.ts +0 -1
- package/dist/utils/settings.js +0 -4
- package/dist/utils/settings.js.map +0 -1
- package/dist/utils/streaming-analyzer.d.ts +0 -160
- package/dist/utils/streaming-analyzer.js +0 -214
- package/dist/utils/streaming-analyzer.js.map +0 -1
|
@@ -1,730 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tree-sitter Parser
|
|
3
|
-
*
|
|
4
|
-
* Base class for tree-sitter based language parsers.
|
|
5
|
-
* Uses WebAssembly (WASM) for cross-platform compatibility.
|
|
6
|
-
*
|
|
7
|
-
* Supports: Python, Rust, Go, TypeScript, JavaScript, HTML, CSS, and 30+ more languages
|
|
8
|
-
*/
|
|
9
|
-
import { Parser, Language } from 'web-tree-sitter';
|
|
10
|
-
import { readFile } from 'fs/promises';
|
|
11
|
-
import { existsSync } from 'fs';
|
|
12
|
-
import { join, dirname } from 'path';
|
|
13
|
-
import { fileURLToPath } from 'url';
|
|
14
|
-
import { BaseLanguageParser } from './language-parser.js';
|
|
15
|
-
// Singleton parser instance (shared across all language parsers)
|
|
16
|
-
let parserInitialized = false;
|
|
17
|
-
let parserInstance = null;
|
|
18
|
-
// Language cache to avoid reloading WASM files
|
|
19
|
-
const languageCache = new Map();
|
|
20
|
-
/**
|
|
21
|
-
* Get non-null children from a node
|
|
22
|
-
*/
|
|
23
|
-
function getChildren(node) {
|
|
24
|
-
return node.children.filter((c) => c !== null);
|
|
25
|
-
}
|
|
26
|
-
/**
|
|
27
|
-
* Find a child node matching a predicate
|
|
28
|
-
*/
|
|
29
|
-
function findChild(node, predicate) {
|
|
30
|
-
return getChildren(node).find(predicate);
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* Check if any child matches a predicate
|
|
34
|
-
*/
|
|
35
|
-
function someChild(node, predicate) {
|
|
36
|
-
return getChildren(node).some(predicate);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Initialize the tree-sitter parser (called once)
|
|
40
|
-
*/
|
|
41
|
-
async function initParser() {
|
|
42
|
-
if (parserInstance && parserInitialized) {
|
|
43
|
-
return parserInstance;
|
|
44
|
-
}
|
|
45
|
-
await Parser.init();
|
|
46
|
-
parserInstance = new Parser();
|
|
47
|
-
parserInitialized = true;
|
|
48
|
-
return parserInstance;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Get the path to the WASM file for a language
|
|
52
|
-
*/
|
|
53
|
-
function getWasmPath(languageName) {
|
|
54
|
-
// Try to find in node_modules/tree-sitter-wasms/out/
|
|
55
|
-
const possiblePaths = [
|
|
56
|
-
join(process.cwd(), 'node_modules', 'tree-sitter-wasms', 'out', `tree-sitter-${languageName}.wasm`),
|
|
57
|
-
join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'node_modules', 'tree-sitter-wasms', 'out', `tree-sitter-${languageName}.wasm`),
|
|
58
|
-
];
|
|
59
|
-
for (const path of possiblePaths) {
|
|
60
|
-
if (existsSync(path)) {
|
|
61
|
-
return path;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
throw new Error(`WASM file not found for language: ${languageName}. Tried: ${possiblePaths.join(', ')}`);
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Load a language grammar
|
|
68
|
-
*/
|
|
69
|
-
async function loadLanguage(languageName) {
|
|
70
|
-
// Check cache first
|
|
71
|
-
const cached = languageCache.get(languageName);
|
|
72
|
-
if (cached) {
|
|
73
|
-
return cached;
|
|
74
|
-
}
|
|
75
|
-
const wasmPath = getWasmPath(languageName);
|
|
76
|
-
const language = await Language.load(wasmPath);
|
|
77
|
-
languageCache.set(languageName, language);
|
|
78
|
-
return language;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Tree-sitter based language parser
|
|
82
|
-
*/
|
|
83
|
-
export class TreeSitterParser extends BaseLanguageParser {
|
|
84
|
-
language;
|
|
85
|
-
treeSitterLanguage;
|
|
86
|
-
parser = null;
|
|
87
|
-
loadedLanguage = null;
|
|
88
|
-
constructor(language, treeSitterLanguage) {
|
|
89
|
-
super();
|
|
90
|
-
this.language = language;
|
|
91
|
-
// Map our language names to tree-sitter grammar names
|
|
92
|
-
this.treeSitterLanguage = treeSitterLanguage || this.mapLanguageToTreeSitter(language);
|
|
93
|
-
}
|
|
94
|
-
mapLanguageToTreeSitter(language) {
|
|
95
|
-
const mapping = {
|
|
96
|
-
'typescript': 'typescript',
|
|
97
|
-
'javascript': 'javascript',
|
|
98
|
-
'python': 'python',
|
|
99
|
-
'rust': 'rust',
|
|
100
|
-
'go': 'go',
|
|
101
|
-
'c': 'c',
|
|
102
|
-
'cpp': 'cpp',
|
|
103
|
-
'swift': 'swift',
|
|
104
|
-
'html': 'html',
|
|
105
|
-
'css': 'css',
|
|
106
|
-
'unknown': 'javascript', // fallback
|
|
107
|
-
};
|
|
108
|
-
return mapping[language];
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Ensure parser is initialized
|
|
112
|
-
*/
|
|
113
|
-
async ensureInitialized() {
|
|
114
|
-
if (!this.parser) {
|
|
115
|
-
this.parser = await initParser();
|
|
116
|
-
}
|
|
117
|
-
if (!this.loadedLanguage) {
|
|
118
|
-
this.loadedLanguage = await loadLanguage(this.treeSitterLanguage);
|
|
119
|
-
this.parser.setLanguage(this.loadedLanguage);
|
|
120
|
-
}
|
|
121
|
-
return { parser: this.parser, language: this.loadedLanguage };
|
|
122
|
-
}
|
|
123
|
-
async parseFile(filePath) {
|
|
124
|
-
try {
|
|
125
|
-
const content = await readFile(filePath, 'utf-8');
|
|
126
|
-
return this.parseContent(content, filePath);
|
|
127
|
-
}
|
|
128
|
-
catch (error) {
|
|
129
|
-
console.warn(`Failed to parse file ${filePath}:`, error);
|
|
130
|
-
return this.createEmptyASTInfo(filePath);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
async parseContent(content, filePath = 'temp') {
|
|
134
|
-
try {
|
|
135
|
-
const { parser } = await this.ensureInitialized();
|
|
136
|
-
const tree = parser.parse(content);
|
|
137
|
-
if (!tree) {
|
|
138
|
-
return this.createEmptyASTInfo(filePath);
|
|
139
|
-
}
|
|
140
|
-
const functions = this.extractFunctions(tree.rootNode);
|
|
141
|
-
const classes = this.extractClasses(tree.rootNode);
|
|
142
|
-
const imports = this.extractImports(tree.rootNode);
|
|
143
|
-
const exports = this.extractExports(tree.rootNode);
|
|
144
|
-
return Object.freeze({
|
|
145
|
-
filePath,
|
|
146
|
-
functions: Object.freeze(functions),
|
|
147
|
-
classes: Object.freeze(classes),
|
|
148
|
-
imports: Object.freeze(imports),
|
|
149
|
-
exports: Object.freeze(exports),
|
|
150
|
-
totalLines: content.split('\n').length,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
catch (error) {
|
|
154
|
-
console.warn(`Failed to parse content:`, error);
|
|
155
|
-
return this.createEmptyASTInfo(filePath);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Extract functions from AST
|
|
160
|
-
*/
|
|
161
|
-
extractFunctions(rootNode) {
|
|
162
|
-
const functions = [];
|
|
163
|
-
const functionTypes = this.getFunctionNodeTypes();
|
|
164
|
-
const visit = (node) => {
|
|
165
|
-
if (functionTypes.includes(node.type)) {
|
|
166
|
-
const funcInfo = this.extractFunctionInfo(node);
|
|
167
|
-
if (funcInfo) {
|
|
168
|
-
functions.push(funcInfo);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
for (const child of getChildren(node)) {
|
|
172
|
-
visit(child);
|
|
173
|
-
}
|
|
174
|
-
};
|
|
175
|
-
visit(rootNode);
|
|
176
|
-
return functions;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Get node types that represent functions for this language
|
|
180
|
-
*/
|
|
181
|
-
getFunctionNodeTypes() {
|
|
182
|
-
switch (this.language) {
|
|
183
|
-
case 'python':
|
|
184
|
-
return ['function_definition', 'async_function_definition'];
|
|
185
|
-
case 'rust':
|
|
186
|
-
return ['function_item', 'impl_item'];
|
|
187
|
-
case 'go':
|
|
188
|
-
return ['function_declaration', 'method_declaration'];
|
|
189
|
-
case 'typescript':
|
|
190
|
-
case 'javascript':
|
|
191
|
-
return ['function_declaration', 'function_expression', 'arrow_function', 'method_definition'];
|
|
192
|
-
case 'c':
|
|
193
|
-
return ['function_definition'];
|
|
194
|
-
case 'cpp':
|
|
195
|
-
return ['function_definition', 'template_declaration'];
|
|
196
|
-
case 'swift':
|
|
197
|
-
return ['function_declaration', 'init_declaration', 'deinit_declaration'];
|
|
198
|
-
case 'html':
|
|
199
|
-
case 'css':
|
|
200
|
-
return []; // No functions in HTML/CSS
|
|
201
|
-
default:
|
|
202
|
-
return ['function_declaration', 'function_definition'];
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Extract function info from a function node
|
|
207
|
-
*/
|
|
208
|
-
extractFunctionInfo(node) {
|
|
209
|
-
try {
|
|
210
|
-
const name = this.extractFunctionName(node);
|
|
211
|
-
const parameters = this.extractParameters(node);
|
|
212
|
-
const returnType = this.extractReturnType(node);
|
|
213
|
-
const startLine = node.startPosition.row + 1;
|
|
214
|
-
const endLine = node.endPosition.row + 1;
|
|
215
|
-
const isAsync = this.isAsyncFunction(node);
|
|
216
|
-
const isExported = this.isExportedFunction(node);
|
|
217
|
-
return Object.freeze({
|
|
218
|
-
name,
|
|
219
|
-
parameters: Object.freeze(parameters),
|
|
220
|
-
returnType,
|
|
221
|
-
startLine,
|
|
222
|
-
endLine,
|
|
223
|
-
complexity: this.calculateComplexity(node),
|
|
224
|
-
length: endLine - startLine + 1,
|
|
225
|
-
isAsync,
|
|
226
|
-
isExported,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
catch {
|
|
230
|
-
return null;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Extract function name
|
|
235
|
-
*/
|
|
236
|
-
extractFunctionName(node) {
|
|
237
|
-
// Find the name/identifier child
|
|
238
|
-
const nameNode = node.childForFieldName('name') ||
|
|
239
|
-
findChild(node, c => c.type === 'identifier' || c.type === 'property_identifier');
|
|
240
|
-
return nameNode?.text || '<anonymous>';
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Extract parameters from function
|
|
244
|
-
*/
|
|
245
|
-
extractParameters(node) {
|
|
246
|
-
const params = [];
|
|
247
|
-
const paramsNode = node.childForFieldName('parameters') ||
|
|
248
|
-
findChild(node, c => c.type === 'parameters' || c.type === 'parameter_list' || c.type === 'formal_parameters');
|
|
249
|
-
if (!paramsNode)
|
|
250
|
-
return params;
|
|
251
|
-
for (const child of getChildren(paramsNode)) {
|
|
252
|
-
if (this.isParameterNode(child)) {
|
|
253
|
-
const paramInfo = this.extractParameterInfo(child);
|
|
254
|
-
if (paramInfo) {
|
|
255
|
-
params.push(paramInfo);
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
return params;
|
|
260
|
-
}
|
|
261
|
-
/**
|
|
262
|
-
* Check if node is a parameter
|
|
263
|
-
*/
|
|
264
|
-
isParameterNode(node) {
|
|
265
|
-
const paramTypes = [
|
|
266
|
-
'parameter', 'required_parameter', 'optional_parameter',
|
|
267
|
-
'identifier', 'typed_parameter', 'default_parameter',
|
|
268
|
-
'formal_parameter',
|
|
269
|
-
];
|
|
270
|
-
return paramTypes.includes(node.type);
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Extract parameter info
|
|
274
|
-
*/
|
|
275
|
-
extractParameterInfo(node) {
|
|
276
|
-
try {
|
|
277
|
-
const nameNode = node.childForFieldName('name') ||
|
|
278
|
-
findChild(node, c => c.type === 'identifier') ||
|
|
279
|
-
node;
|
|
280
|
-
const typeNode = node.childForFieldName('type') ||
|
|
281
|
-
findChild(node, c => c.type === 'type_annotation' || c.type === 'type');
|
|
282
|
-
const defaultNode = node.childForFieldName('value') ||
|
|
283
|
-
findChild(node, c => c.type === 'default_value');
|
|
284
|
-
return Object.freeze({
|
|
285
|
-
name: nameNode.text,
|
|
286
|
-
type: typeNode?.text,
|
|
287
|
-
isOptional: node.type === 'optional_parameter' || !!defaultNode,
|
|
288
|
-
hasDefault: !!defaultNode,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
catch {
|
|
292
|
-
return null;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* Extract return type
|
|
297
|
-
*/
|
|
298
|
-
extractReturnType(node) {
|
|
299
|
-
const returnTypeNode = node.childForFieldName('return_type') ||
|
|
300
|
-
findChild(node, c => c.type === 'type_annotation' || c.type === 'return_type');
|
|
301
|
-
return returnTypeNode?.text;
|
|
302
|
-
}
|
|
303
|
-
/**
|
|
304
|
-
* Check if function is async
|
|
305
|
-
*/
|
|
306
|
-
isAsyncFunction(node) {
|
|
307
|
-
if (node.type.includes('async'))
|
|
308
|
-
return true;
|
|
309
|
-
return someChild(node, c => c.type === 'async');
|
|
310
|
-
}
|
|
311
|
-
/**
|
|
312
|
-
* Check if function is exported
|
|
313
|
-
*/
|
|
314
|
-
isExportedFunction(node) {
|
|
315
|
-
// Check parent for export statement
|
|
316
|
-
const parent = node.parent;
|
|
317
|
-
if (!parent)
|
|
318
|
-
return false;
|
|
319
|
-
if (parent.type === 'export_statement' || parent.type === 'export_declaration') {
|
|
320
|
-
return true;
|
|
321
|
-
}
|
|
322
|
-
// Python/Go: check for public naming convention
|
|
323
|
-
if (this.language === 'python' || this.language === 'go') {
|
|
324
|
-
const name = this.extractFunctionName(node);
|
|
325
|
-
// Python: no underscore prefix, Go: uppercase first letter
|
|
326
|
-
if (this.language === 'go') {
|
|
327
|
-
return name.length > 0 && name[0] === name[0].toUpperCase();
|
|
328
|
-
}
|
|
329
|
-
return !name.startsWith('_');
|
|
330
|
-
}
|
|
331
|
-
// Rust: check for pub keyword
|
|
332
|
-
if (this.language === 'rust') {
|
|
333
|
-
return someChild(node, c => c.type === 'visibility_modifier' && c.text === 'pub');
|
|
334
|
-
}
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
/**
|
|
338
|
-
* Calculate cyclomatic complexity
|
|
339
|
-
*/
|
|
340
|
-
calculateComplexity(node) {
|
|
341
|
-
let complexity = 1;
|
|
342
|
-
const decisionPoints = [
|
|
343
|
-
'if_statement', 'if_expression', 'elif_clause', 'else_clause',
|
|
344
|
-
'for_statement', 'for_expression', 'while_statement', 'while_expression',
|
|
345
|
-
'match_expression', 'match_arm', 'case_clause',
|
|
346
|
-
'try_statement', 'catch_clause', 'except_clause',
|
|
347
|
-
'conditional_expression', 'ternary_expression',
|
|
348
|
-
'binary_expression', // for && and ||
|
|
349
|
-
];
|
|
350
|
-
const visit = (n) => {
|
|
351
|
-
if (decisionPoints.includes(n.type)) {
|
|
352
|
-
complexity++;
|
|
353
|
-
}
|
|
354
|
-
// Count && and || operators
|
|
355
|
-
if (n.type === 'binary_expression') {
|
|
356
|
-
const operator = findChild(n, c => c.type === '&&' || c.type === '||' || c.text === '&&' || c.text === '||' || c.text === 'and' || c.text === 'or');
|
|
357
|
-
if (operator) {
|
|
358
|
-
complexity++;
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
for (const child of getChildren(n)) {
|
|
362
|
-
visit(child);
|
|
363
|
-
}
|
|
364
|
-
};
|
|
365
|
-
visit(node);
|
|
366
|
-
return complexity;
|
|
367
|
-
}
|
|
368
|
-
/**
|
|
369
|
-
* Extract classes from AST
|
|
370
|
-
*/
|
|
371
|
-
extractClasses(rootNode) {
|
|
372
|
-
const classes = [];
|
|
373
|
-
const classTypes = this.getClassNodeTypes();
|
|
374
|
-
const visit = (node) => {
|
|
375
|
-
if (classTypes.includes(node.type)) {
|
|
376
|
-
const classInfo = this.extractClassInfo(node);
|
|
377
|
-
if (classInfo) {
|
|
378
|
-
classes.push(classInfo);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
for (const child of getChildren(node)) {
|
|
382
|
-
visit(child);
|
|
383
|
-
}
|
|
384
|
-
};
|
|
385
|
-
visit(rootNode);
|
|
386
|
-
return classes;
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* Get node types that represent classes
|
|
390
|
-
*/
|
|
391
|
-
getClassNodeTypes() {
|
|
392
|
-
switch (this.language) {
|
|
393
|
-
case 'python':
|
|
394
|
-
return ['class_definition'];
|
|
395
|
-
case 'rust':
|
|
396
|
-
return ['struct_item', 'enum_item', 'trait_item'];
|
|
397
|
-
case 'go':
|
|
398
|
-
return ['type_declaration']; // Go uses structs
|
|
399
|
-
case 'typescript':
|
|
400
|
-
case 'javascript':
|
|
401
|
-
return ['class_declaration', 'class'];
|
|
402
|
-
case 'c':
|
|
403
|
-
return ['struct_specifier', 'enum_specifier', 'union_specifier'];
|
|
404
|
-
case 'cpp':
|
|
405
|
-
return ['class_specifier', 'struct_specifier', 'enum_specifier', 'union_specifier'];
|
|
406
|
-
case 'swift':
|
|
407
|
-
return ['class_declaration', 'struct_declaration', 'enum_declaration', 'protocol_declaration'];
|
|
408
|
-
case 'html':
|
|
409
|
-
case 'css':
|
|
410
|
-
return []; // No classes in HTML/CSS (CSS has selectors, not class definitions)
|
|
411
|
-
default:
|
|
412
|
-
return ['class_declaration', 'class_definition'];
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* Extract class info
|
|
417
|
-
*/
|
|
418
|
-
extractClassInfo(node) {
|
|
419
|
-
try {
|
|
420
|
-
const nameNode = node.childForFieldName('name') ||
|
|
421
|
-
findChild(node, c => c.type === 'identifier' || c.type === 'type_identifier');
|
|
422
|
-
const name = nameNode?.text || '<anonymous>';
|
|
423
|
-
const methods = this.extractMethods(node);
|
|
424
|
-
const properties = this.extractProperties(node);
|
|
425
|
-
const startLine = node.startPosition.row + 1;
|
|
426
|
-
const endLine = node.endPosition.row + 1;
|
|
427
|
-
// Extract extends/implements
|
|
428
|
-
let extendsClass;
|
|
429
|
-
const implementsInterfaces = [];
|
|
430
|
-
const superclassNode = node.childForFieldName('superclass') ||
|
|
431
|
-
findChild(node, c => c.type === 'argument_list' || c.type === 'superclass');
|
|
432
|
-
if (superclassNode) {
|
|
433
|
-
extendsClass = superclassNode.text;
|
|
434
|
-
}
|
|
435
|
-
return Object.freeze({
|
|
436
|
-
name,
|
|
437
|
-
methods: Object.freeze(methods),
|
|
438
|
-
properties: Object.freeze(properties),
|
|
439
|
-
startLine,
|
|
440
|
-
endLine,
|
|
441
|
-
length: endLine - startLine + 1,
|
|
442
|
-
isExported: this.isExportedClass(node, name),
|
|
443
|
-
extendsClass,
|
|
444
|
-
implementsInterfaces: Object.freeze(implementsInterfaces),
|
|
445
|
-
});
|
|
446
|
-
}
|
|
447
|
-
catch {
|
|
448
|
-
return null;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
/**
|
|
452
|
-
* Check if class is exported
|
|
453
|
-
*/
|
|
454
|
-
isExportedClass(node, name) {
|
|
455
|
-
const parent = node.parent;
|
|
456
|
-
if (parent?.type === 'export_statement')
|
|
457
|
-
return true;
|
|
458
|
-
if (this.language === 'go') {
|
|
459
|
-
return name.length > 0 && name[0] === name[0].toUpperCase();
|
|
460
|
-
}
|
|
461
|
-
if (this.language === 'python') {
|
|
462
|
-
return !name.startsWith('_');
|
|
463
|
-
}
|
|
464
|
-
if (this.language === 'rust') {
|
|
465
|
-
return someChild(node, c => c.type === 'visibility_modifier' && c.text === 'pub');
|
|
466
|
-
}
|
|
467
|
-
return false;
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* Extract methods from class
|
|
471
|
-
*/
|
|
472
|
-
extractMethods(classNode) {
|
|
473
|
-
const methods = [];
|
|
474
|
-
const bodyNode = classNode.childForFieldName('body') ||
|
|
475
|
-
findChild(classNode, c => c.type === 'class_body' || c.type === 'block' || c.type === 'declaration_list');
|
|
476
|
-
if (!bodyNode)
|
|
477
|
-
return methods;
|
|
478
|
-
for (const child of getChildren(bodyNode)) {
|
|
479
|
-
if (this.getFunctionNodeTypes().includes(child.type) || child.type === 'method_definition') {
|
|
480
|
-
const funcInfo = this.extractFunctionInfo(child);
|
|
481
|
-
if (funcInfo) {
|
|
482
|
-
methods.push(Object.freeze({
|
|
483
|
-
...funcInfo,
|
|
484
|
-
visibility: this.getVisibility(child),
|
|
485
|
-
isStatic: this.isStatic(child),
|
|
486
|
-
}));
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
return methods;
|
|
491
|
-
}
|
|
492
|
-
/**
|
|
493
|
-
* Get method visibility
|
|
494
|
-
*/
|
|
495
|
-
getVisibility(node) {
|
|
496
|
-
const name = this.extractFunctionName(node);
|
|
497
|
-
// Python naming convention
|
|
498
|
-
if (this.language === 'python') {
|
|
499
|
-
if (name.startsWith('__') && !name.endsWith('__'))
|
|
500
|
-
return 'private';
|
|
501
|
-
if (name.startsWith('_'))
|
|
502
|
-
return 'protected';
|
|
503
|
-
return 'public';
|
|
504
|
-
}
|
|
505
|
-
// TypeScript/JavaScript modifiers
|
|
506
|
-
if (someChild(node, c => c.text === 'private' || c.type === 'private'))
|
|
507
|
-
return 'private';
|
|
508
|
-
if (someChild(node, c => c.text === 'protected' || c.type === 'protected'))
|
|
509
|
-
return 'protected';
|
|
510
|
-
// Rust visibility
|
|
511
|
-
if (this.language === 'rust') {
|
|
512
|
-
const hasPublic = someChild(node, c => c.type === 'visibility_modifier' && c.text === 'pub');
|
|
513
|
-
return hasPublic ? 'public' : 'private';
|
|
514
|
-
}
|
|
515
|
-
return 'public';
|
|
516
|
-
}
|
|
517
|
-
/**
|
|
518
|
-
* Check if method is static
|
|
519
|
-
*/
|
|
520
|
-
isStatic(node) {
|
|
521
|
-
return someChild(node, c => c.text === 'static' || c.type === 'static');
|
|
522
|
-
}
|
|
523
|
-
/**
|
|
524
|
-
* Extract properties from class
|
|
525
|
-
*/
|
|
526
|
-
extractProperties(classNode) {
|
|
527
|
-
const properties = [];
|
|
528
|
-
const bodyNode = classNode.childForFieldName('body') ||
|
|
529
|
-
findChild(classNode, c => c.type === 'class_body' || c.type === 'block' || c.type === 'field_declaration_list');
|
|
530
|
-
if (!bodyNode)
|
|
531
|
-
return properties;
|
|
532
|
-
const propertyTypes = ['property_definition', 'public_field_definition', 'field_declaration', 'assignment'];
|
|
533
|
-
for (const child of getChildren(bodyNode)) {
|
|
534
|
-
if (propertyTypes.includes(child.type)) {
|
|
535
|
-
const nameNode = child.childForFieldName('name') ||
|
|
536
|
-
findChild(child, c => c.type === 'identifier' || c.type === 'property_identifier');
|
|
537
|
-
if (nameNode) {
|
|
538
|
-
const typeNode = child.childForFieldName('type') ||
|
|
539
|
-
findChild(child, c => c.type === 'type_annotation');
|
|
540
|
-
properties.push(Object.freeze({
|
|
541
|
-
name: nameNode.text,
|
|
542
|
-
type: typeNode?.text,
|
|
543
|
-
visibility: 'public',
|
|
544
|
-
isReadonly: someChild(child, c => c.text === 'readonly'),
|
|
545
|
-
isStatic: someChild(child, c => c.text === 'static'),
|
|
546
|
-
hasInitializer: someChild(child, c => c.type === 'initializer' || c.type === '='),
|
|
547
|
-
}));
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
return properties;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Extract imports from AST
|
|
555
|
-
*/
|
|
556
|
-
extractImports(rootNode) {
|
|
557
|
-
const imports = [];
|
|
558
|
-
const importTypes = this.getImportNodeTypes();
|
|
559
|
-
const visit = (node) => {
|
|
560
|
-
if (importTypes.includes(node.type)) {
|
|
561
|
-
const importInfo = this.extractImportInfo(node);
|
|
562
|
-
if (importInfo) {
|
|
563
|
-
imports.push(importInfo);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
for (const child of getChildren(node)) {
|
|
567
|
-
visit(child);
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
visit(rootNode);
|
|
571
|
-
return imports;
|
|
572
|
-
}
|
|
573
|
-
/**
|
|
574
|
-
* Get import node types for this language
|
|
575
|
-
*/
|
|
576
|
-
getImportNodeTypes() {
|
|
577
|
-
switch (this.language) {
|
|
578
|
-
case 'python':
|
|
579
|
-
return ['import_statement', 'import_from_statement'];
|
|
580
|
-
case 'rust':
|
|
581
|
-
return ['use_declaration'];
|
|
582
|
-
case 'go':
|
|
583
|
-
return ['import_declaration', 'import_spec'];
|
|
584
|
-
case 'typescript':
|
|
585
|
-
case 'javascript':
|
|
586
|
-
return ['import_statement', 'import_declaration'];
|
|
587
|
-
case 'c':
|
|
588
|
-
case 'cpp':
|
|
589
|
-
return ['preproc_include']; // #include directives
|
|
590
|
-
case 'swift':
|
|
591
|
-
return ['import_declaration'];
|
|
592
|
-
case 'html':
|
|
593
|
-
return ['script_element', 'style_element']; // <script src="..."> and <style>
|
|
594
|
-
case 'css':
|
|
595
|
-
return ['import_statement', 'at_rule']; // @import rules
|
|
596
|
-
default:
|
|
597
|
-
return ['import_statement', 'import_declaration'];
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
/**
|
|
601
|
-
* Extract import info
|
|
602
|
-
*/
|
|
603
|
-
extractImportInfo(node) {
|
|
604
|
-
try {
|
|
605
|
-
let moduleSpecifier = '';
|
|
606
|
-
const namedImports = [];
|
|
607
|
-
let defaultImport;
|
|
608
|
-
let namespaceImport;
|
|
609
|
-
// Python: import x or from x import y
|
|
610
|
-
if (this.language === 'python') {
|
|
611
|
-
const moduleNode = node.childForFieldName('module_name') ||
|
|
612
|
-
findChild(node, c => c.type === 'dotted_name');
|
|
613
|
-
moduleSpecifier = moduleNode?.text || '';
|
|
614
|
-
const nameNode = findChild(node, c => c.type === 'aliased_import' || c.type === 'dotted_name');
|
|
615
|
-
if (nameNode) {
|
|
616
|
-
namedImports.push(nameNode.text);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
// TypeScript/JavaScript
|
|
620
|
-
else if (this.language === 'typescript' || this.language === 'javascript') {
|
|
621
|
-
const sourceNode = node.childForFieldName('source') ||
|
|
622
|
-
findChild(node, c => c.type === 'string');
|
|
623
|
-
moduleSpecifier = sourceNode?.text?.replace(/['"]/g, '') || '';
|
|
624
|
-
for (const child of getChildren(node)) {
|
|
625
|
-
if (child.type === 'import_clause') {
|
|
626
|
-
for (const clauseChild of getChildren(child)) {
|
|
627
|
-
if (clauseChild.type === 'identifier') {
|
|
628
|
-
defaultImport = clauseChild.text;
|
|
629
|
-
}
|
|
630
|
-
else if (clauseChild.type === 'named_imports') {
|
|
631
|
-
for (const spec of getChildren(clauseChild)) {
|
|
632
|
-
if (spec.type === 'import_specifier') {
|
|
633
|
-
namedImports.push(spec.text);
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
else if (clauseChild.type === 'namespace_import') {
|
|
638
|
-
namespaceImport = clauseChild.text;
|
|
639
|
-
}
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
}
|
|
643
|
-
}
|
|
644
|
-
// Rust: use x::y
|
|
645
|
-
else if (this.language === 'rust') {
|
|
646
|
-
const pathNode = findChild(node, c => c.type === 'use_tree' || c.type === 'scoped_identifier');
|
|
647
|
-
moduleSpecifier = pathNode?.text || '';
|
|
648
|
-
}
|
|
649
|
-
// Go: import "x"
|
|
650
|
-
else if (this.language === 'go') {
|
|
651
|
-
const pathNode = findChild(node, c => c.type === 'interpreted_string_literal');
|
|
652
|
-
moduleSpecifier = pathNode?.text?.replace(/"/g, '') || '';
|
|
653
|
-
}
|
|
654
|
-
const isExternal = !moduleSpecifier.startsWith('.') && !moduleSpecifier.startsWith('/');
|
|
655
|
-
return Object.freeze({
|
|
656
|
-
moduleSpecifier,
|
|
657
|
-
namedImports: Object.freeze(namedImports),
|
|
658
|
-
defaultImport,
|
|
659
|
-
namespaceImport,
|
|
660
|
-
isExternal,
|
|
661
|
-
isTypeOnly: node.text?.includes('type ') || false,
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
catch {
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
/**
|
|
669
|
-
* Extract exports from AST
|
|
670
|
-
*/
|
|
671
|
-
extractExports(rootNode) {
|
|
672
|
-
const exports = [];
|
|
673
|
-
// For Python/Rust/Go, exports are determined by naming conventions or visibility modifiers
|
|
674
|
-
// which are handled in isExported* methods
|
|
675
|
-
// For TypeScript/JavaScript, look for export statements
|
|
676
|
-
if (this.language === 'typescript' || this.language === 'javascript') {
|
|
677
|
-
const visit = (node) => {
|
|
678
|
-
if (node.type === 'export_statement' || node.type === 'export_declaration') {
|
|
679
|
-
const declaration = findChild(node, c => c.type === 'function_declaration' ||
|
|
680
|
-
c.type === 'class_declaration' ||
|
|
681
|
-
c.type === 'variable_declaration');
|
|
682
|
-
if (declaration) {
|
|
683
|
-
const nameNode = declaration.childForFieldName('name') ||
|
|
684
|
-
findChild(declaration, c => c.type === 'identifier');
|
|
685
|
-
if (nameNode) {
|
|
686
|
-
exports.push(Object.freeze({
|
|
687
|
-
name: nameNode.text,
|
|
688
|
-
isDefault: node.text?.includes('export default') || false,
|
|
689
|
-
type: declaration.type.includes('function') ? 'function' :
|
|
690
|
-
declaration.type.includes('class') ? 'class' : 'variable',
|
|
691
|
-
}));
|
|
692
|
-
}
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
for (const child of getChildren(node)) {
|
|
696
|
-
visit(child);
|
|
697
|
-
}
|
|
698
|
-
};
|
|
699
|
-
visit(rootNode);
|
|
700
|
-
}
|
|
701
|
-
return exports;
|
|
702
|
-
}
|
|
703
|
-
/**
|
|
704
|
-
* Get the raw syntax tree (for advanced usage)
|
|
705
|
-
*/
|
|
706
|
-
async getTree(content) {
|
|
707
|
-
const { parser } = await this.ensureInitialized();
|
|
708
|
-
return parser.parse(content);
|
|
709
|
-
}
|
|
710
|
-
dispose() {
|
|
711
|
-
// Parser is shared, don't dispose it here
|
|
712
|
-
this.loadedLanguage = null;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Create a parser for a specific language
|
|
717
|
-
*/
|
|
718
|
-
export function createTreeSitterParser(language) {
|
|
719
|
-
return new TreeSitterParser(language);
|
|
720
|
-
}
|
|
721
|
-
/**
|
|
722
|
-
* Supported tree-sitter languages (beyond our core 5)
|
|
723
|
-
*/
|
|
724
|
-
export const TREE_SITTER_LANGUAGES = [
|
|
725
|
-
'bash', 'c', 'cpp', 'c_sharp', 'css', 'dart', 'elixir', 'elm',
|
|
726
|
-
'go', 'html', 'java', 'javascript', 'json', 'kotlin', 'lua',
|
|
727
|
-
'objc', 'ocaml', 'php', 'python', 'ruby', 'rust', 'scala',
|
|
728
|
-
'solidity', 'swift', 'toml', 'tsx', 'typescript', 'vue', 'yaml', 'zig',
|
|
729
|
-
];
|
|
730
|
-
//# sourceMappingURL=tree-sitter-parser.js.map
|