@optave/codegraph 2.6.0 → 3.0.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/README.md +109 -52
- package/package.json +5 -5
- package/src/ast.js +392 -0
- package/src/batch.js +93 -3
- package/src/builder.js +314 -95
- package/src/cfg.js +1451 -0
- package/src/change-journal.js +130 -0
- package/src/cli.js +411 -139
- package/src/complexity.js +8 -8
- package/src/dataflow.js +1187 -0
- package/src/db.js +96 -0
- package/src/embedder.js +16 -16
- package/src/export.js +305 -0
- package/src/extractors/csharp.js +64 -1
- package/src/extractors/go.js +66 -1
- package/src/extractors/hcl.js +22 -0
- package/src/extractors/java.js +61 -1
- package/src/extractors/javascript.js +142 -0
- package/src/extractors/php.js +79 -0
- package/src/extractors/python.js +134 -0
- package/src/extractors/ruby.js +89 -0
- package/src/extractors/rust.js +71 -1
- package/src/index.js +51 -3
- package/src/mcp.js +403 -222
- package/src/paginate.js +3 -3
- package/src/parser.js +8 -0
- package/src/queries.js +362 -36
- package/src/structure.js +4 -1
- package/src/viewer.js +948 -0
- package/src/watcher.js +36 -1
package/src/extractors/python.js
CHANGED
|
@@ -22,12 +22,14 @@ export function extractPythonSymbols(tree, _filePath) {
|
|
|
22
22
|
const parentClass = findPythonParentClass(node);
|
|
23
23
|
const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
|
|
24
24
|
const kind = parentClass ? 'method' : 'function';
|
|
25
|
+
const fnChildren = extractPythonParameters(node);
|
|
25
26
|
definitions.push({
|
|
26
27
|
name: fullName,
|
|
27
28
|
kind,
|
|
28
29
|
line: node.startPosition.row + 1,
|
|
29
30
|
endLine: nodeEndLine(node),
|
|
30
31
|
decorators,
|
|
32
|
+
children: fnChildren.length > 0 ? fnChildren : undefined,
|
|
31
33
|
});
|
|
32
34
|
}
|
|
33
35
|
break;
|
|
@@ -36,11 +38,13 @@ export function extractPythonSymbols(tree, _filePath) {
|
|
|
36
38
|
case 'class_definition': {
|
|
37
39
|
const nameNode = node.childForFieldName('name');
|
|
38
40
|
if (nameNode) {
|
|
41
|
+
const clsChildren = extractPythonClassProperties(node);
|
|
39
42
|
definitions.push({
|
|
40
43
|
name: nameNode.text,
|
|
41
44
|
kind: 'class',
|
|
42
45
|
line: node.startPosition.row + 1,
|
|
43
46
|
endLine: nodeEndLine(node),
|
|
47
|
+
children: clsChildren.length > 0 ? clsChildren : undefined,
|
|
44
48
|
});
|
|
45
49
|
const superclasses =
|
|
46
50
|
node.childForFieldName('superclasses') || findChild(node, 'argument_list');
|
|
@@ -108,6 +112,24 @@ export function extractPythonSymbols(tree, _filePath) {
|
|
|
108
112
|
break;
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
case 'expression_statement': {
|
|
116
|
+
// Module-level UPPER_CASE assignments → constants
|
|
117
|
+
if (node.parent && node.parent.type === 'module') {
|
|
118
|
+
const assignment = findChild(node, 'assignment');
|
|
119
|
+
if (assignment) {
|
|
120
|
+
const left = assignment.childForFieldName('left');
|
|
121
|
+
if (left && left.type === 'identifier' && /^[A-Z_][A-Z0-9_]*$/.test(left.text)) {
|
|
122
|
+
definitions.push({
|
|
123
|
+
name: left.text,
|
|
124
|
+
kind: 'constant',
|
|
125
|
+
line: node.startPosition.row + 1,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
|
|
111
133
|
case 'import_from_statement': {
|
|
112
134
|
let source = '';
|
|
113
135
|
const names = [];
|
|
@@ -133,6 +155,118 @@ export function extractPythonSymbols(tree, _filePath) {
|
|
|
133
155
|
for (let i = 0; i < node.childCount; i++) walkPythonNode(node.child(i));
|
|
134
156
|
}
|
|
135
157
|
|
|
158
|
+
function extractPythonParameters(fnNode) {
|
|
159
|
+
const params = [];
|
|
160
|
+
const paramsNode = fnNode.childForFieldName('parameters') || findChild(fnNode, 'parameters');
|
|
161
|
+
if (!paramsNode) return params;
|
|
162
|
+
for (let i = 0; i < paramsNode.childCount; i++) {
|
|
163
|
+
const child = paramsNode.child(i);
|
|
164
|
+
if (!child) continue;
|
|
165
|
+
const t = child.type;
|
|
166
|
+
if (t === 'identifier') {
|
|
167
|
+
params.push({ name: child.text, kind: 'parameter', line: child.startPosition.row + 1 });
|
|
168
|
+
} else if (
|
|
169
|
+
t === 'typed_parameter' ||
|
|
170
|
+
t === 'default_parameter' ||
|
|
171
|
+
t === 'typed_default_parameter'
|
|
172
|
+
) {
|
|
173
|
+
const nameNode = child.childForFieldName('name') || child.child(0);
|
|
174
|
+
if (nameNode && nameNode.type === 'identifier') {
|
|
175
|
+
params.push({
|
|
176
|
+
name: nameNode.text,
|
|
177
|
+
kind: 'parameter',
|
|
178
|
+
line: child.startPosition.row + 1,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
} else if (t === 'list_splat_pattern' || t === 'dictionary_splat_pattern') {
|
|
182
|
+
// *args, **kwargs
|
|
183
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
184
|
+
const inner = child.child(j);
|
|
185
|
+
if (inner && inner.type === 'identifier') {
|
|
186
|
+
params.push({ name: inner.text, kind: 'parameter', line: child.startPosition.row + 1 });
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return params;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function extractPythonClassProperties(classNode) {
|
|
196
|
+
const props = [];
|
|
197
|
+
const seen = new Set();
|
|
198
|
+
const body = classNode.childForFieldName('body') || findChild(classNode, 'block');
|
|
199
|
+
if (!body) return props;
|
|
200
|
+
|
|
201
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
202
|
+
const child = body.child(i);
|
|
203
|
+
if (!child) continue;
|
|
204
|
+
|
|
205
|
+
// Direct class attribute assignments: x = 5
|
|
206
|
+
if (child.type === 'expression_statement') {
|
|
207
|
+
const assignment = findChild(child, 'assignment');
|
|
208
|
+
if (assignment) {
|
|
209
|
+
const left = assignment.childForFieldName('left');
|
|
210
|
+
if (left && left.type === 'identifier' && !seen.has(left.text)) {
|
|
211
|
+
seen.add(left.text);
|
|
212
|
+
props.push({ name: left.text, kind: 'property', line: child.startPosition.row + 1 });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// __init__ method: self.x = ... assignments
|
|
218
|
+
if (child.type === 'function_definition') {
|
|
219
|
+
const fnName = child.childForFieldName('name');
|
|
220
|
+
if (fnName && fnName.text === '__init__') {
|
|
221
|
+
const initBody = child.childForFieldName('body') || findChild(child, 'block');
|
|
222
|
+
if (initBody) {
|
|
223
|
+
walkInitBody(initBody, seen, props);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// decorated __init__
|
|
229
|
+
if (child.type === 'decorated_definition') {
|
|
230
|
+
for (let j = 0; j < child.childCount; j++) {
|
|
231
|
+
const inner = child.child(j);
|
|
232
|
+
if (inner && inner.type === 'function_definition') {
|
|
233
|
+
const fnName = inner.childForFieldName('name');
|
|
234
|
+
if (fnName && fnName.text === '__init__') {
|
|
235
|
+
const initBody = inner.childForFieldName('body') || findChild(inner, 'block');
|
|
236
|
+
if (initBody) {
|
|
237
|
+
walkInitBody(initBody, seen, props);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return props;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function walkInitBody(bodyNode, seen, props) {
|
|
248
|
+
for (let i = 0; i < bodyNode.childCount; i++) {
|
|
249
|
+
const stmt = bodyNode.child(i);
|
|
250
|
+
if (!stmt || stmt.type !== 'expression_statement') continue;
|
|
251
|
+
const assignment = findChild(stmt, 'assignment');
|
|
252
|
+
if (!assignment) continue;
|
|
253
|
+
const left = assignment.childForFieldName('left');
|
|
254
|
+
if (!left || left.type !== 'attribute') continue;
|
|
255
|
+
const obj = left.childForFieldName('object');
|
|
256
|
+
const attr = left.childForFieldName('attribute');
|
|
257
|
+
if (
|
|
258
|
+
obj &&
|
|
259
|
+
obj.text === 'self' &&
|
|
260
|
+
attr &&
|
|
261
|
+
attr.type === 'identifier' &&
|
|
262
|
+
!seen.has(attr.text)
|
|
263
|
+
) {
|
|
264
|
+
seen.add(attr.text);
|
|
265
|
+
props.push({ name: attr.text, kind: 'property', line: stmt.startPosition.row + 1 });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
136
270
|
function findPythonParentClass(node) {
|
|
137
271
|
let current = node.parent;
|
|
138
272
|
while (current) {
|
package/src/extractors/ruby.js
CHANGED
|
@@ -31,11 +31,13 @@ export function extractRubySymbols(tree, _filePath) {
|
|
|
31
31
|
case 'class': {
|
|
32
32
|
const nameNode = node.childForFieldName('name');
|
|
33
33
|
if (nameNode) {
|
|
34
|
+
const classChildren = extractRubyClassChildren(node);
|
|
34
35
|
definitions.push({
|
|
35
36
|
name: nameNode.text,
|
|
36
37
|
kind: 'class',
|
|
37
38
|
line: node.startPosition.row + 1,
|
|
38
39
|
endLine: nodeEndLine(node),
|
|
40
|
+
children: classChildren.length > 0 ? classChildren : undefined,
|
|
39
41
|
});
|
|
40
42
|
const superclass = node.childForFieldName('superclass');
|
|
41
43
|
if (superclass) {
|
|
@@ -73,11 +75,13 @@ export function extractRubySymbols(tree, _filePath) {
|
|
|
73
75
|
case 'module': {
|
|
74
76
|
const nameNode = node.childForFieldName('name');
|
|
75
77
|
if (nameNode) {
|
|
78
|
+
const moduleChildren = extractRubyBodyConstants(node);
|
|
76
79
|
definitions.push({
|
|
77
80
|
name: nameNode.text,
|
|
78
81
|
kind: 'module',
|
|
79
82
|
line: node.startPosition.row + 1,
|
|
80
83
|
endLine: nodeEndLine(node),
|
|
84
|
+
children: moduleChildren.length > 0 ? moduleChildren : undefined,
|
|
81
85
|
});
|
|
82
86
|
}
|
|
83
87
|
break;
|
|
@@ -88,11 +92,13 @@ export function extractRubySymbols(tree, _filePath) {
|
|
|
88
92
|
if (nameNode) {
|
|
89
93
|
const parentClass = findRubyParentClass(node);
|
|
90
94
|
const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
|
|
95
|
+
const params = extractRubyParameters(node);
|
|
91
96
|
definitions.push({
|
|
92
97
|
name: fullName,
|
|
93
98
|
kind: 'method',
|
|
94
99
|
line: node.startPosition.row + 1,
|
|
95
100
|
endLine: nodeEndLine(node),
|
|
101
|
+
children: params.length > 0 ? params : undefined,
|
|
96
102
|
});
|
|
97
103
|
}
|
|
98
104
|
break;
|
|
@@ -103,16 +109,34 @@ export function extractRubySymbols(tree, _filePath) {
|
|
|
103
109
|
if (nameNode) {
|
|
104
110
|
const parentClass = findRubyParentClass(node);
|
|
105
111
|
const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
|
|
112
|
+
const params = extractRubyParameters(node);
|
|
106
113
|
definitions.push({
|
|
107
114
|
name: fullName,
|
|
108
115
|
kind: 'function',
|
|
109
116
|
line: node.startPosition.row + 1,
|
|
110
117
|
endLine: nodeEndLine(node),
|
|
118
|
+
children: params.length > 0 ? params : undefined,
|
|
111
119
|
});
|
|
112
120
|
}
|
|
113
121
|
break;
|
|
114
122
|
}
|
|
115
123
|
|
|
124
|
+
case 'assignment': {
|
|
125
|
+
// Top-level constant assignments (parent is program)
|
|
126
|
+
if (node.parent && node.parent.type === 'program') {
|
|
127
|
+
const left = node.childForFieldName('left');
|
|
128
|
+
if (left && left.type === 'constant') {
|
|
129
|
+
definitions.push({
|
|
130
|
+
name: left.text,
|
|
131
|
+
kind: 'constant',
|
|
132
|
+
line: node.startPosition.row + 1,
|
|
133
|
+
endLine: nodeEndLine(node),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
116
140
|
case 'call': {
|
|
117
141
|
const methodNode = node.childForFieldName('method');
|
|
118
142
|
if (methodNode) {
|
|
@@ -186,3 +210,68 @@ export function extractRubySymbols(tree, _filePath) {
|
|
|
186
210
|
walkRubyNode(tree.rootNode);
|
|
187
211
|
return { definitions, calls, imports, classes, exports };
|
|
188
212
|
}
|
|
213
|
+
|
|
214
|
+
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
const RUBY_PARAM_TYPES = new Set([
|
|
217
|
+
'identifier',
|
|
218
|
+
'optional_parameter',
|
|
219
|
+
'splat_parameter',
|
|
220
|
+
'hash_splat_parameter',
|
|
221
|
+
'block_parameter',
|
|
222
|
+
'keyword_parameter',
|
|
223
|
+
]);
|
|
224
|
+
|
|
225
|
+
function extractRubyParameters(methodNode) {
|
|
226
|
+
const params = [];
|
|
227
|
+
const paramList =
|
|
228
|
+
methodNode.childForFieldName('parameters') || findChild(methodNode, 'method_parameters');
|
|
229
|
+
if (!paramList) return params;
|
|
230
|
+
for (let i = 0; i < paramList.childCount; i++) {
|
|
231
|
+
const param = paramList.child(i);
|
|
232
|
+
if (!param || !RUBY_PARAM_TYPES.has(param.type)) continue;
|
|
233
|
+
let name;
|
|
234
|
+
if (param.type === 'identifier') {
|
|
235
|
+
name = param.text;
|
|
236
|
+
} else {
|
|
237
|
+
// Compound parameter types have an identifier child for the name
|
|
238
|
+
const id = findChild(param, 'identifier');
|
|
239
|
+
name = id ? id.text : param.text;
|
|
240
|
+
}
|
|
241
|
+
params.push({ name, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
242
|
+
}
|
|
243
|
+
return params;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function extractRubyBodyConstants(containerNode) {
|
|
247
|
+
const children = [];
|
|
248
|
+
const body = containerNode.childForFieldName('body') || findChild(containerNode, 'body');
|
|
249
|
+
if (!body) return children;
|
|
250
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
251
|
+
const child = body.child(i);
|
|
252
|
+
if (!child || child.type !== 'assignment') continue;
|
|
253
|
+
const left = child.childForFieldName('left');
|
|
254
|
+
if (left && left.type === 'constant') {
|
|
255
|
+
children.push({ name: left.text, kind: 'constant', line: child.startPosition.row + 1 });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return children;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function extractRubyClassChildren(classNode) {
|
|
262
|
+
const children = [];
|
|
263
|
+
const body = classNode.childForFieldName('body') || findChild(classNode, 'body');
|
|
264
|
+
if (!body) return children;
|
|
265
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
266
|
+
const child = body.child(i);
|
|
267
|
+
if (!child || child.type !== 'assignment') continue;
|
|
268
|
+
const left = child.childForFieldName('left');
|
|
269
|
+
if (!left) continue;
|
|
270
|
+
if (left.type === 'instance_variable') {
|
|
271
|
+
children.push({ name: left.text, kind: 'property', line: child.startPosition.row + 1 });
|
|
272
|
+
} else if (left.type === 'constant') {
|
|
273
|
+
children.push({ name: left.text, kind: 'constant', line: child.startPosition.row + 1 });
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return children;
|
|
277
|
+
}
|
package/src/extractors/rust.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { nodeEndLine } from './helpers.js';
|
|
1
|
+
import { findChild, nodeEndLine } from './helpers.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Extract symbols from Rust files.
|
|
@@ -30,11 +30,13 @@ export function extractRustSymbols(tree, _filePath) {
|
|
|
30
30
|
const implType = findCurrentImpl(node);
|
|
31
31
|
const fullName = implType ? `${implType}.${nameNode.text}` : nameNode.text;
|
|
32
32
|
const kind = implType ? 'method' : 'function';
|
|
33
|
+
const params = extractRustParameters(node.childForFieldName('parameters'));
|
|
33
34
|
definitions.push({
|
|
34
35
|
name: fullName,
|
|
35
36
|
kind,
|
|
36
37
|
line: node.startPosition.row + 1,
|
|
37
38
|
endLine: nodeEndLine(node),
|
|
39
|
+
children: params.length > 0 ? params : undefined,
|
|
38
40
|
});
|
|
39
41
|
}
|
|
40
42
|
break;
|
|
@@ -43,11 +45,13 @@ export function extractRustSymbols(tree, _filePath) {
|
|
|
43
45
|
case 'struct_item': {
|
|
44
46
|
const nameNode = node.childForFieldName('name');
|
|
45
47
|
if (nameNode) {
|
|
48
|
+
const fields = extractStructFields(node);
|
|
46
49
|
definitions.push({
|
|
47
50
|
name: nameNode.text,
|
|
48
51
|
kind: 'struct',
|
|
49
52
|
line: node.startPosition.row + 1,
|
|
50
53
|
endLine: nodeEndLine(node),
|
|
54
|
+
children: fields.length > 0 ? fields : undefined,
|
|
51
55
|
});
|
|
52
56
|
}
|
|
53
57
|
break;
|
|
@@ -56,11 +60,26 @@ export function extractRustSymbols(tree, _filePath) {
|
|
|
56
60
|
case 'enum_item': {
|
|
57
61
|
const nameNode = node.childForFieldName('name');
|
|
58
62
|
if (nameNode) {
|
|
63
|
+
const variants = extractEnumVariants(node);
|
|
59
64
|
definitions.push({
|
|
60
65
|
name: nameNode.text,
|
|
61
66
|
kind: 'enum',
|
|
62
67
|
line: node.startPosition.row + 1,
|
|
63
68
|
endLine: nodeEndLine(node),
|
|
69
|
+
children: variants.length > 0 ? variants : undefined,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
case 'const_item': {
|
|
76
|
+
const nameNode = node.childForFieldName('name');
|
|
77
|
+
if (nameNode) {
|
|
78
|
+
definitions.push({
|
|
79
|
+
name: nameNode.text,
|
|
80
|
+
kind: 'constant',
|
|
81
|
+
line: node.startPosition.row + 1,
|
|
82
|
+
endLine: nodeEndLine(node),
|
|
64
83
|
});
|
|
65
84
|
}
|
|
66
85
|
break;
|
|
@@ -170,6 +189,57 @@ export function extractRustSymbols(tree, _filePath) {
|
|
|
170
189
|
return { definitions, calls, imports, classes, exports };
|
|
171
190
|
}
|
|
172
191
|
|
|
192
|
+
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
193
|
+
|
|
194
|
+
function extractRustParameters(paramListNode) {
|
|
195
|
+
const params = [];
|
|
196
|
+
if (!paramListNode) return params;
|
|
197
|
+
for (let i = 0; i < paramListNode.childCount; i++) {
|
|
198
|
+
const param = paramListNode.child(i);
|
|
199
|
+
if (!param) continue;
|
|
200
|
+
if (param.type === 'self_parameter') {
|
|
201
|
+
params.push({ name: 'self', kind: 'parameter', line: param.startPosition.row + 1 });
|
|
202
|
+
} else if (param.type === 'parameter') {
|
|
203
|
+
const pattern = param.childForFieldName('pattern');
|
|
204
|
+
if (pattern) {
|
|
205
|
+
params.push({ name: pattern.text, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return params;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function extractStructFields(structNode) {
|
|
213
|
+
const fields = [];
|
|
214
|
+
const fieldList =
|
|
215
|
+
structNode.childForFieldName('body') || findChild(structNode, 'field_declaration_list');
|
|
216
|
+
if (!fieldList) return fields;
|
|
217
|
+
for (let i = 0; i < fieldList.childCount; i++) {
|
|
218
|
+
const field = fieldList.child(i);
|
|
219
|
+
if (!field || field.type !== 'field_declaration') continue;
|
|
220
|
+
const nameNode = field.childForFieldName('name');
|
|
221
|
+
if (nameNode) {
|
|
222
|
+
fields.push({ name: nameNode.text, kind: 'property', line: field.startPosition.row + 1 });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return fields;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function extractEnumVariants(enumNode) {
|
|
229
|
+
const variants = [];
|
|
230
|
+
const body = enumNode.childForFieldName('body') || findChild(enumNode, 'enum_variant_list');
|
|
231
|
+
if (!body) return variants;
|
|
232
|
+
for (let i = 0; i < body.childCount; i++) {
|
|
233
|
+
const variant = body.child(i);
|
|
234
|
+
if (!variant || variant.type !== 'enum_variant') continue;
|
|
235
|
+
const nameNode = variant.childForFieldName('name');
|
|
236
|
+
if (nameNode) {
|
|
237
|
+
variants.push({ name: nameNode.text, kind: 'constant', line: variant.startPosition.row + 1 });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return variants;
|
|
241
|
+
}
|
|
242
|
+
|
|
173
243
|
function extractRustUsePath(node) {
|
|
174
244
|
if (!node) return [];
|
|
175
245
|
|
package/src/index.js
CHANGED
|
@@ -5,16 +5,35 @@
|
|
|
5
5
|
* import { buildGraph, queryNameData, findCycles, exportDOT } from 'codegraph';
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
// AST node queries
|
|
9
|
+
export { AST_NODE_KINDS, astQuery, astQueryData } from './ast.js';
|
|
8
10
|
// Audit (composite report)
|
|
9
11
|
export { audit, auditData } from './audit.js';
|
|
10
12
|
// Batch querying
|
|
11
|
-
export {
|
|
13
|
+
export {
|
|
14
|
+
BATCH_COMMANDS,
|
|
15
|
+
batch,
|
|
16
|
+
batchData,
|
|
17
|
+
batchQuery,
|
|
18
|
+
multiBatchData,
|
|
19
|
+
splitTargets,
|
|
20
|
+
} from './batch.js';
|
|
12
21
|
// Architecture boundary rules
|
|
13
22
|
export { evaluateBoundaries, PRESETS, validateBoundaryConfig } from './boundaries.js';
|
|
14
23
|
// Branch comparison
|
|
15
24
|
export { branchCompareData, branchCompareMermaid } from './branch-compare.js';
|
|
16
25
|
// Graph building
|
|
17
26
|
export { buildGraph, collectFiles, loadPathAliases, resolveImportPath } from './builder.js';
|
|
27
|
+
// Control flow graph (intraprocedural)
|
|
28
|
+
export {
|
|
29
|
+
buildCFGData,
|
|
30
|
+
buildFunctionCFG,
|
|
31
|
+
CFG_RULES,
|
|
32
|
+
cfg,
|
|
33
|
+
cfgData,
|
|
34
|
+
cfgToDOT,
|
|
35
|
+
cfgToMermaid,
|
|
36
|
+
} from './cfg.js';
|
|
18
37
|
// Check (CI validation predicates)
|
|
19
38
|
export { check, checkData } from './check.js';
|
|
20
39
|
// Co-change analysis
|
|
@@ -37,6 +56,7 @@ export {
|
|
|
37
56
|
computeHalsteadMetrics,
|
|
38
57
|
computeLOCMetrics,
|
|
39
58
|
computeMaintainabilityIndex,
|
|
59
|
+
findFunctionNode,
|
|
40
60
|
HALSTEAD_RULES,
|
|
41
61
|
iterComplexity,
|
|
42
62
|
} from './complexity.js';
|
|
@@ -46,6 +66,15 @@ export { loadConfig } from './config.js';
|
|
|
46
66
|
export { EXTENSIONS, IGNORE_DIRS, normalizePath } from './constants.js';
|
|
47
67
|
// Circular dependency detection
|
|
48
68
|
export { findCycles, formatCycles } from './cycles.js';
|
|
69
|
+
// Dataflow analysis
|
|
70
|
+
export {
|
|
71
|
+
buildDataflowEdges,
|
|
72
|
+
dataflow,
|
|
73
|
+
dataflowData,
|
|
74
|
+
dataflowImpactData,
|
|
75
|
+
dataflowPathData,
|
|
76
|
+
extractDataflow,
|
|
77
|
+
} from './dataflow.js';
|
|
49
78
|
// Database utilities
|
|
50
79
|
export {
|
|
51
80
|
findDbPath,
|
|
@@ -71,8 +100,15 @@ export {
|
|
|
71
100
|
search,
|
|
72
101
|
searchData,
|
|
73
102
|
} from './embedder.js';
|
|
74
|
-
// Export (DOT/Mermaid/JSON)
|
|
75
|
-
export {
|
|
103
|
+
// Export (DOT/Mermaid/JSON/GraphML/GraphSON/Neo4j CSV)
|
|
104
|
+
export {
|
|
105
|
+
exportDOT,
|
|
106
|
+
exportGraphML,
|
|
107
|
+
exportGraphSON,
|
|
108
|
+
exportJSON,
|
|
109
|
+
exportMermaid,
|
|
110
|
+
exportNeo4jCSV,
|
|
111
|
+
} from './export.js';
|
|
76
112
|
// Execution flow tracing
|
|
77
113
|
export { entryPointType, flowData, listEntryPointsData } from './flow.js';
|
|
78
114
|
// Logger
|
|
@@ -91,13 +127,21 @@ export { getActiveEngine, parseFileAuto, parseFilesAuto } from './parser.js';
|
|
|
91
127
|
// Query functions (data-returning)
|
|
92
128
|
export {
|
|
93
129
|
ALL_SYMBOL_KINDS,
|
|
130
|
+
CORE_EDGE_KINDS,
|
|
131
|
+
CORE_SYMBOL_KINDS,
|
|
132
|
+
childrenData,
|
|
94
133
|
contextData,
|
|
95
134
|
diffImpactData,
|
|
96
135
|
diffImpactMermaid,
|
|
136
|
+
EVERY_EDGE_KIND,
|
|
137
|
+
EVERY_SYMBOL_KIND,
|
|
138
|
+
EXTENDED_SYMBOL_KINDS,
|
|
97
139
|
explainData,
|
|
140
|
+
exportsData,
|
|
98
141
|
FALSE_POSITIVE_CALLER_THRESHOLD,
|
|
99
142
|
FALSE_POSITIVE_NAMES,
|
|
100
143
|
fileDepsData,
|
|
144
|
+
fileExports,
|
|
101
145
|
fnDepsData,
|
|
102
146
|
fnImpactData,
|
|
103
147
|
impactAnalysisData,
|
|
@@ -106,9 +150,11 @@ export {
|
|
|
106
150
|
iterWhere,
|
|
107
151
|
kindIcon,
|
|
108
152
|
moduleMapData,
|
|
153
|
+
normalizeSymbol,
|
|
109
154
|
pathData,
|
|
110
155
|
queryNameData,
|
|
111
156
|
rolesData,
|
|
157
|
+
STRUCTURAL_EDGE_KINDS,
|
|
112
158
|
statsData,
|
|
113
159
|
VALID_ROLES,
|
|
114
160
|
whereData,
|
|
@@ -147,5 +193,7 @@ export {
|
|
|
147
193
|
} from './structure.js';
|
|
148
194
|
// Triage — composite risk audit
|
|
149
195
|
export { triage, triageData } from './triage.js';
|
|
196
|
+
// Interactive HTML viewer
|
|
197
|
+
export { generatePlotHTML, loadPlotConfig } from './viewer.js';
|
|
150
198
|
// Watch mode
|
|
151
199
|
export { watchProject } from './watcher.js';
|