@optave/codegraph 2.0.0 → 2.1.1-dev.3c12b64

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.
@@ -0,0 +1,167 @@
1
+ import { nodeEndLine } from './helpers.js';
2
+
3
+ /**
4
+ * Extract symbols from Go files.
5
+ */
6
+ export function extractGoSymbols(tree, _filePath) {
7
+ const definitions = [];
8
+ const calls = [];
9
+ const imports = [];
10
+ const classes = [];
11
+ const exports = [];
12
+
13
+ function walkGoNode(node) {
14
+ switch (node.type) {
15
+ case 'function_declaration': {
16
+ const nameNode = node.childForFieldName('name');
17
+ if (nameNode) {
18
+ definitions.push({
19
+ name: nameNode.text,
20
+ kind: 'function',
21
+ line: node.startPosition.row + 1,
22
+ endLine: nodeEndLine(node),
23
+ });
24
+ }
25
+ break;
26
+ }
27
+
28
+ case 'method_declaration': {
29
+ const nameNode = node.childForFieldName('name');
30
+ const receiver = node.childForFieldName('receiver');
31
+ if (nameNode) {
32
+ let receiverType = null;
33
+ if (receiver) {
34
+ // receiver is a parameter_list like (r *Foo) or (r Foo)
35
+ for (let i = 0; i < receiver.childCount; i++) {
36
+ const param = receiver.child(i);
37
+ if (!param) continue;
38
+ const typeNode = param.childForFieldName('type');
39
+ if (typeNode) {
40
+ receiverType =
41
+ typeNode.type === 'pointer_type'
42
+ ? typeNode.text.replace(/^\*/, '')
43
+ : typeNode.text;
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ const fullName = receiverType ? `${receiverType}.${nameNode.text}` : nameNode.text;
49
+ definitions.push({
50
+ name: fullName,
51
+ kind: 'method',
52
+ line: node.startPosition.row + 1,
53
+ endLine: nodeEndLine(node),
54
+ });
55
+ }
56
+ break;
57
+ }
58
+
59
+ case 'type_declaration': {
60
+ for (let i = 0; i < node.childCount; i++) {
61
+ const spec = node.child(i);
62
+ if (!spec || spec.type !== 'type_spec') continue;
63
+ const nameNode = spec.childForFieldName('name');
64
+ const typeNode = spec.childForFieldName('type');
65
+ if (nameNode && typeNode) {
66
+ if (typeNode.type === 'struct_type') {
67
+ definitions.push({
68
+ name: nameNode.text,
69
+ kind: 'struct',
70
+ line: node.startPosition.row + 1,
71
+ endLine: nodeEndLine(node),
72
+ });
73
+ } else if (typeNode.type === 'interface_type') {
74
+ definitions.push({
75
+ name: nameNode.text,
76
+ kind: 'interface',
77
+ line: node.startPosition.row + 1,
78
+ endLine: nodeEndLine(node),
79
+ });
80
+ for (let j = 0; j < typeNode.childCount; j++) {
81
+ const member = typeNode.child(j);
82
+ if (member && member.type === 'method_elem') {
83
+ const methName = member.childForFieldName('name');
84
+ if (methName) {
85
+ definitions.push({
86
+ name: `${nameNode.text}.${methName.text}`,
87
+ kind: 'method',
88
+ line: member.startPosition.row + 1,
89
+ endLine: member.endPosition.row + 1,
90
+ });
91
+ }
92
+ }
93
+ }
94
+ } else {
95
+ definitions.push({
96
+ name: nameNode.text,
97
+ kind: 'type',
98
+ line: node.startPosition.row + 1,
99
+ endLine: nodeEndLine(node),
100
+ });
101
+ }
102
+ }
103
+ }
104
+ break;
105
+ }
106
+
107
+ case 'import_declaration': {
108
+ for (let i = 0; i < node.childCount; i++) {
109
+ const child = node.child(i);
110
+ if (!child) continue;
111
+ if (child.type === 'import_spec') {
112
+ const pathNode = child.childForFieldName('path');
113
+ if (pathNode) {
114
+ const importPath = pathNode.text.replace(/"/g, '');
115
+ const nameNode = child.childForFieldName('name');
116
+ const alias = nameNode ? nameNode.text : importPath.split('/').pop();
117
+ imports.push({
118
+ source: importPath,
119
+ names: [alias],
120
+ line: child.startPosition.row + 1,
121
+ goImport: true,
122
+ });
123
+ }
124
+ }
125
+ if (child.type === 'import_spec_list') {
126
+ for (let j = 0; j < child.childCount; j++) {
127
+ const spec = child.child(j);
128
+ if (spec && spec.type === 'import_spec') {
129
+ const pathNode = spec.childForFieldName('path');
130
+ if (pathNode) {
131
+ const importPath = pathNode.text.replace(/"/g, '');
132
+ const nameNode = spec.childForFieldName('name');
133
+ const alias = nameNode ? nameNode.text : importPath.split('/').pop();
134
+ imports.push({
135
+ source: importPath,
136
+ names: [alias],
137
+ line: spec.startPosition.row + 1,
138
+ goImport: true,
139
+ });
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ break;
146
+ }
147
+
148
+ case 'call_expression': {
149
+ const fn = node.childForFieldName('function');
150
+ if (fn) {
151
+ if (fn.type === 'identifier') {
152
+ calls.push({ name: fn.text, line: node.startPosition.row + 1 });
153
+ } else if (fn.type === 'selector_expression') {
154
+ const field = fn.childForFieldName('field');
155
+ if (field) calls.push({ name: field.text, line: node.startPosition.row + 1 });
156
+ }
157
+ }
158
+ break;
159
+ }
160
+ }
161
+
162
+ for (let i = 0; i < node.childCount; i++) walkGoNode(node.child(i));
163
+ }
164
+
165
+ walkGoNode(tree.rootNode);
166
+ return { definitions, calls, imports, classes, exports };
167
+ }
@@ -0,0 +1,73 @@
1
+ import { nodeEndLine } from './helpers.js';
2
+
3
+ /**
4
+ * Extract symbols from HCL (Terraform) files.
5
+ */
6
+ export function extractHCLSymbols(tree, _filePath) {
7
+ const definitions = [];
8
+ const imports = [];
9
+
10
+ function walkHclNode(node) {
11
+ if (node.type === 'block') {
12
+ const children = [];
13
+ for (let i = 0; i < node.childCount; i++) children.push(node.child(i));
14
+
15
+ const identifiers = children.filter((c) => c.type === 'identifier');
16
+ const strings = children.filter((c) => c.type === 'string_lit');
17
+
18
+ if (identifiers.length > 0) {
19
+ const blockType = identifiers[0].text;
20
+ let name = '';
21
+
22
+ if (blockType === 'resource' && strings.length >= 2) {
23
+ name = `${strings[0].text.replace(/"/g, '')}.${strings[1].text.replace(/"/g, '')}`;
24
+ } else if (blockType === 'data' && strings.length >= 2) {
25
+ name = `data.${strings[0].text.replace(/"/g, '')}.${strings[1].text.replace(/"/g, '')}`;
26
+ } else if (
27
+ (blockType === 'variable' || blockType === 'output' || blockType === 'module') &&
28
+ strings.length >= 1
29
+ ) {
30
+ name = `${blockType}.${strings[0].text.replace(/"/g, '')}`;
31
+ } else if (blockType === 'locals') {
32
+ name = 'locals';
33
+ } else if (blockType === 'terraform' || blockType === 'provider') {
34
+ name = blockType;
35
+ if (strings.length >= 1) name += `.${strings[0].text.replace(/"/g, '')}`;
36
+ }
37
+
38
+ if (name) {
39
+ definitions.push({
40
+ name,
41
+ kind: blockType,
42
+ line: node.startPosition.row + 1,
43
+ endLine: nodeEndLine(node),
44
+ });
45
+ }
46
+
47
+ if (blockType === 'module') {
48
+ const body = children.find((c) => c.type === 'body');
49
+ if (body) {
50
+ for (let i = 0; i < body.childCount; i++) {
51
+ const attr = body.child(i);
52
+ if (attr && attr.type === 'attribute') {
53
+ const key = attr.childForFieldName('key') || attr.child(0);
54
+ const val = attr.childForFieldName('val') || attr.child(2);
55
+ if (key && key.text === 'source' && val) {
56
+ const src = val.text.replace(/"/g, '');
57
+ if (src.startsWith('./') || src.startsWith('../')) {
58
+ imports.push({ source: src, names: [], line: attr.startPosition.row + 1 });
59
+ }
60
+ }
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ }
67
+
68
+ for (let i = 0; i < node.childCount; i++) walkHclNode(node.child(i));
69
+ }
70
+
71
+ walkHclNode(tree.rootNode);
72
+ return { definitions, calls: [], imports, classes: [], exports: [] };
73
+ }
@@ -0,0 +1,10 @@
1
+ export function nodeEndLine(node) {
2
+ return node.endPosition.row + 1;
3
+ }
4
+
5
+ export function findChild(node, type) {
6
+ for (let i = 0; i < node.childCount; i++) {
7
+ if (node.child(i).type === type) return node.child(i);
8
+ }
9
+ return null;
10
+ }
@@ -0,0 +1,9 @@
1
+ export { extractCSharpSymbols } from './csharp.js';
2
+ export { extractGoSymbols } from './go.js';
3
+ export { extractHCLSymbols } from './hcl.js';
4
+ export { extractJavaSymbols } from './java.js';
5
+ export { extractSymbols } from './javascript.js';
6
+ export { extractPHPSymbols } from './php.js';
7
+ export { extractPythonSymbols } from './python.js';
8
+ export { extractRubySymbols } from './ruby.js';
9
+ export { extractRustSymbols } from './rust.js';
@@ -0,0 +1,227 @@
1
+ import { nodeEndLine } from './helpers.js';
2
+
3
+ /**
4
+ * Extract symbols from Java files.
5
+ */
6
+ export function extractJavaSymbols(tree, _filePath) {
7
+ const definitions = [];
8
+ const calls = [];
9
+ const imports = [];
10
+ const classes = [];
11
+ const exports = [];
12
+
13
+ function findJavaParentClass(node) {
14
+ let current = node.parent;
15
+ while (current) {
16
+ if (
17
+ current.type === 'class_declaration' ||
18
+ current.type === 'enum_declaration' ||
19
+ current.type === 'interface_declaration'
20
+ ) {
21
+ const nameNode = current.childForFieldName('name');
22
+ return nameNode ? nameNode.text : null;
23
+ }
24
+ current = current.parent;
25
+ }
26
+ return null;
27
+ }
28
+
29
+ function walkJavaNode(node) {
30
+ switch (node.type) {
31
+ case 'class_declaration': {
32
+ const nameNode = node.childForFieldName('name');
33
+ if (nameNode) {
34
+ definitions.push({
35
+ name: nameNode.text,
36
+ kind: 'class',
37
+ line: node.startPosition.row + 1,
38
+ endLine: nodeEndLine(node),
39
+ });
40
+
41
+ const superclass = node.childForFieldName('superclass');
42
+ if (superclass) {
43
+ for (let i = 0; i < superclass.childCount; i++) {
44
+ const child = superclass.child(i);
45
+ if (
46
+ child &&
47
+ (child.type === 'type_identifier' ||
48
+ child.type === 'identifier' ||
49
+ child.type === 'generic_type')
50
+ ) {
51
+ const superName = child.type === 'generic_type' ? child.child(0)?.text : child.text;
52
+ if (superName)
53
+ classes.push({
54
+ name: nameNode.text,
55
+ extends: superName,
56
+ line: node.startPosition.row + 1,
57
+ });
58
+ break;
59
+ }
60
+ }
61
+ }
62
+
63
+ const interfaces = node.childForFieldName('interfaces');
64
+ if (interfaces) {
65
+ for (let i = 0; i < interfaces.childCount; i++) {
66
+ const child = interfaces.child(i);
67
+ if (
68
+ child &&
69
+ (child.type === 'type_identifier' ||
70
+ child.type === 'identifier' ||
71
+ child.type === 'type_list' ||
72
+ child.type === 'generic_type')
73
+ ) {
74
+ if (child.type === 'type_list') {
75
+ for (let j = 0; j < child.childCount; j++) {
76
+ const t = child.child(j);
77
+ if (
78
+ t &&
79
+ (t.type === 'type_identifier' ||
80
+ t.type === 'identifier' ||
81
+ t.type === 'generic_type')
82
+ ) {
83
+ const ifaceName = t.type === 'generic_type' ? t.child(0)?.text : t.text;
84
+ if (ifaceName)
85
+ classes.push({
86
+ name: nameNode.text,
87
+ implements: ifaceName,
88
+ line: node.startPosition.row + 1,
89
+ });
90
+ }
91
+ }
92
+ } else {
93
+ const ifaceName =
94
+ child.type === 'generic_type' ? child.child(0)?.text : child.text;
95
+ if (ifaceName)
96
+ classes.push({
97
+ name: nameNode.text,
98
+ implements: ifaceName,
99
+ line: node.startPosition.row + 1,
100
+ });
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ break;
107
+ }
108
+
109
+ case 'interface_declaration': {
110
+ const nameNode = node.childForFieldName('name');
111
+ if (nameNode) {
112
+ definitions.push({
113
+ name: nameNode.text,
114
+ kind: 'interface',
115
+ line: node.startPosition.row + 1,
116
+ endLine: nodeEndLine(node),
117
+ });
118
+ const body = node.childForFieldName('body');
119
+ if (body) {
120
+ for (let i = 0; i < body.childCount; i++) {
121
+ const child = body.child(i);
122
+ if (child && child.type === 'method_declaration') {
123
+ const methName = child.childForFieldName('name');
124
+ if (methName) {
125
+ definitions.push({
126
+ name: `${nameNode.text}.${methName.text}`,
127
+ kind: 'method',
128
+ line: child.startPosition.row + 1,
129
+ endLine: child.endPosition.row + 1,
130
+ });
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ break;
137
+ }
138
+
139
+ case 'enum_declaration': {
140
+ const nameNode = node.childForFieldName('name');
141
+ if (nameNode) {
142
+ definitions.push({
143
+ name: nameNode.text,
144
+ kind: 'enum',
145
+ line: node.startPosition.row + 1,
146
+ endLine: nodeEndLine(node),
147
+ });
148
+ }
149
+ break;
150
+ }
151
+
152
+ case 'method_declaration': {
153
+ const nameNode = node.childForFieldName('name');
154
+ if (nameNode) {
155
+ const parentClass = findJavaParentClass(node);
156
+ const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
157
+ definitions.push({
158
+ name: fullName,
159
+ kind: 'method',
160
+ line: node.startPosition.row + 1,
161
+ endLine: nodeEndLine(node),
162
+ });
163
+ }
164
+ break;
165
+ }
166
+
167
+ case 'constructor_declaration': {
168
+ const nameNode = node.childForFieldName('name');
169
+ if (nameNode) {
170
+ const parentClass = findJavaParentClass(node);
171
+ const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
172
+ definitions.push({
173
+ name: fullName,
174
+ kind: 'method',
175
+ line: node.startPosition.row + 1,
176
+ endLine: nodeEndLine(node),
177
+ });
178
+ }
179
+ break;
180
+ }
181
+
182
+ case 'import_declaration': {
183
+ for (let i = 0; i < node.childCount; i++) {
184
+ const child = node.child(i);
185
+ if (child && (child.type === 'scoped_identifier' || child.type === 'identifier')) {
186
+ const fullPath = child.text;
187
+ const lastName = fullPath.split('.').pop();
188
+ imports.push({
189
+ source: fullPath,
190
+ names: [lastName],
191
+ line: node.startPosition.row + 1,
192
+ javaImport: true,
193
+ });
194
+ }
195
+ if (child && child.type === 'asterisk') {
196
+ const lastImport = imports[imports.length - 1];
197
+ if (lastImport) lastImport.names = ['*'];
198
+ }
199
+ }
200
+ break;
201
+ }
202
+
203
+ case 'method_invocation': {
204
+ const nameNode = node.childForFieldName('name');
205
+ if (nameNode) {
206
+ calls.push({ name: nameNode.text, line: node.startPosition.row + 1 });
207
+ }
208
+ break;
209
+ }
210
+
211
+ case 'object_creation_expression': {
212
+ const typeNode = node.childForFieldName('type');
213
+ if (typeNode) {
214
+ const typeName =
215
+ typeNode.type === 'generic_type' ? typeNode.child(0)?.text : typeNode.text;
216
+ if (typeName) calls.push({ name: typeName, line: node.startPosition.row + 1 });
217
+ }
218
+ break;
219
+ }
220
+ }
221
+
222
+ for (let i = 0; i < node.childCount; i++) walkJavaNode(node.child(i));
223
+ }
224
+
225
+ walkJavaNode(tree.rootNode);
226
+ return { definitions, calls, imports, classes, exports };
227
+ }