@kentwynn/kgraph 0.1.26 → 0.2.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 +3 -18
- package/dist/cli/commands/context.d.ts +2 -2
- package/dist/cli/commands/context.js +82 -23
- package/dist/cli/commands/init.js +2 -25
- package/dist/cli/commands/workflow.js +2 -2
- package/dist/cli/help.d.ts +1 -0
- package/dist/cli/help.js +4 -6
- package/dist/cli/index.js +0 -2
- package/dist/cli/init-prompt.d.ts +2 -7
- package/dist/cli/init-prompt.js +0 -63
- package/dist/cli/init-recommendations.d.ts +1 -12
- package/dist/cli/init-recommendations.js +0 -23
- package/dist/cli/init-summary.d.ts +2 -4
- package/dist/cli/init-summary.js +10 -35
- package/dist/config/config.js +0 -33
- package/dist/context/context-query.js +23 -0
- package/dist/scanner/c-symbol-extractor.d.ts +1 -1
- package/dist/scanner/c-symbol-extractor.js +108 -65
- package/dist/scanner/csharp-symbol-extractor.d.ts +1 -1
- package/dist/scanner/csharp-symbol-extractor.js +93 -67
- package/dist/scanner/go-symbol-extractor.d.ts +1 -1
- package/dist/scanner/go-symbol-extractor.js +75 -60
- package/dist/scanner/jvm-symbol-extractor.d.ts +1 -1
- package/dist/scanner/jvm-symbol-extractor.js +139 -71
- package/dist/scanner/python-symbol-extractor.d.ts +1 -1
- package/dist/scanner/python-symbol-extractor.js +92 -71
- package/dist/scanner/repo-scanner.js +65 -8
- package/dist/scanner/rust-symbol-extractor.d.ts +1 -1
- package/dist/scanner/rust-symbol-extractor.js +94 -89
- package/dist/scanner/tree-sitter-parser.d.ts +5 -0
- package/dist/scanner/tree-sitter-parser.js +55 -0
- package/dist/types/cognition.d.ts +3 -2
- package/dist/types/config.d.ts +0 -7
- package/dist/types/maps.d.ts +6 -5
- package/package.json +10 -1
- package/dist/cli/commands/extractor.d.ts +0 -2
- package/dist/cli/commands/extractor.js +0 -50
- package/dist/extractors/extractor-registry.d.ts +0 -11
- package/dist/extractors/extractor-registry.js +0 -70
- package/dist/extractors/extractor-store.d.ts +0 -10
- package/dist/extractors/extractor-store.js +0 -58
|
@@ -1,14 +1,19 @@
|
|
|
1
|
+
import { parseSource } from './tree-sitter-parser.js';
|
|
2
|
+
const CPP_EXTS = new Set(['.cpp', '.cc', '.cxx', '.hpp', '.hxx']);
|
|
1
3
|
// Handles C (.c, .h) and C++ (.cpp, .cc, .cxx, .hpp, .hxx)
|
|
2
|
-
export function extractCSymbols(sourceText, filePath) {
|
|
3
|
-
const lines = sourceText.split('\n');
|
|
4
|
+
export async function extractCSymbols(sourceText, filePath) {
|
|
4
5
|
const symbols = [];
|
|
5
6
|
const dependencies = [];
|
|
6
7
|
const relationships = [];
|
|
7
8
|
const warnings = [];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
if (!sourceText.trim()) {
|
|
10
|
+
return { symbols, dependencies, relationships, warnings };
|
|
11
|
+
}
|
|
12
|
+
const ext = filePath.substring(filePath.lastIndexOf('.'));
|
|
13
|
+
const grammar = CPP_EXTS.has(ext) ? 'cpp' : 'c';
|
|
14
|
+
const tree = await parseSource(sourceText, grammar);
|
|
15
|
+
const addSymbol = (name, kind, startLine, endLine, parentName) => {
|
|
16
|
+
const id = [filePath, kind, parentName, name, startLine]
|
|
12
17
|
.filter(Boolean)
|
|
13
18
|
.join('#');
|
|
14
19
|
symbols.push({
|
|
@@ -16,8 +21,8 @@ export function extractCSymbols(sourceText, filePath) {
|
|
|
16
21
|
name,
|
|
17
22
|
kind,
|
|
18
23
|
filePath,
|
|
19
|
-
startLine
|
|
20
|
-
endLine
|
|
24
|
+
startLine,
|
|
25
|
+
endLine,
|
|
21
26
|
exported: false,
|
|
22
27
|
parentName,
|
|
23
28
|
});
|
|
@@ -30,67 +35,105 @@ export function extractCSymbols(sourceText, filePath) {
|
|
|
30
35
|
confidence: 'high',
|
|
31
36
|
});
|
|
32
37
|
};
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
while (typeStack.length > 0 &&
|
|
42
|
-
braceDepth < typeStack[typeStack.length - 1].braceDepth) {
|
|
43
|
-
typeStack.pop();
|
|
44
|
-
}
|
|
45
|
-
// #include <...> or #include "..."
|
|
46
|
-
const includeMatch = trimmed.match(/^#include\s+[<"]([^>"]+)[>"]/);
|
|
47
|
-
if (includeMatch) {
|
|
48
|
-
const specifier = includeMatch[1];
|
|
49
|
-
const kind = trimmed.includes('"') ? 'local' : 'package';
|
|
50
|
-
dependencies.push({ fromFile: filePath, specifier, kind });
|
|
51
|
-
relationships.push({
|
|
52
|
-
sourceType: 'file',
|
|
53
|
-
sourceId: filePath,
|
|
54
|
-
targetType: kind === 'local' ? 'file' : 'package',
|
|
55
|
-
targetId: specifier,
|
|
56
|
-
relationshipType: 'import',
|
|
57
|
-
confidence: 'high',
|
|
58
|
-
});
|
|
59
|
-
continue;
|
|
38
|
+
function getFuncName(node) {
|
|
39
|
+
// function_definition has a function_declarator child which contains the identifier
|
|
40
|
+
const declarator = node.childForFieldName('declarator');
|
|
41
|
+
if (!declarator)
|
|
42
|
+
return null;
|
|
43
|
+
if (declarator.type === 'function_declarator') {
|
|
44
|
+
const nameNode = declarator.childForFieldName('declarator');
|
|
45
|
+
return nameNode?.text ?? null;
|
|
60
46
|
}
|
|
61
|
-
//
|
|
62
|
-
const
|
|
63
|
-
if (
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
continue;
|
|
47
|
+
// For pointer_declarator wrapping function_declarator
|
|
48
|
+
const funcDecl = declarator.descendantsOfType('function_declarator')[0];
|
|
49
|
+
if (funcDecl) {
|
|
50
|
+
const nameNode = funcDecl.childForFieldName('declarator');
|
|
51
|
+
return nameNode?.text ?? null;
|
|
67
52
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function walk(node, parentClassName) {
|
|
56
|
+
switch (node.type) {
|
|
57
|
+
case 'preproc_include': {
|
|
58
|
+
// #include <...> or #include "..."
|
|
59
|
+
const pathNode = node.namedChildren.find((c) => c.type === 'system_lib_string') ??
|
|
60
|
+
node.namedChildren.find((c) => c.type === 'string_literal');
|
|
61
|
+
if (pathNode) {
|
|
62
|
+
let specifier;
|
|
63
|
+
let kind;
|
|
64
|
+
if (pathNode.type === 'system_lib_string') {
|
|
65
|
+
// <iostream> — strip angle brackets
|
|
66
|
+
specifier = pathNode.text.replace(/^<|>$/g, '');
|
|
67
|
+
kind = 'package';
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
// "myheader.h" — extract string content
|
|
71
|
+
const content = pathNode.namedChildren.find((c) => c.type === 'string_content');
|
|
72
|
+
specifier = content?.text ?? pathNode.text.replace(/^"|"$/g, '');
|
|
73
|
+
kind = 'local';
|
|
74
|
+
}
|
|
75
|
+
dependencies.push({ fromFile: filePath, specifier, kind });
|
|
76
|
+
relationships.push({
|
|
77
|
+
sourceType: 'file',
|
|
78
|
+
sourceId: filePath,
|
|
79
|
+
targetType: kind === 'local' ? 'file' : 'package',
|
|
80
|
+
targetId: specifier,
|
|
81
|
+
relationshipType: 'import',
|
|
82
|
+
confidence: 'high',
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
case 'class_specifier':
|
|
88
|
+
case 'struct_specifier': {
|
|
89
|
+
const nameNode = node.childForFieldName('name');
|
|
90
|
+
if (nameNode) {
|
|
91
|
+
addSymbol(nameNode.text, 'class', node.startPosition.row + 1, node.endPosition.row + 1, parentClassName);
|
|
92
|
+
// Walk body for methods
|
|
93
|
+
const body = node.childForFieldName('body');
|
|
94
|
+
if (body) {
|
|
95
|
+
for (const child of body.namedChildren) {
|
|
96
|
+
walk(child, nameNode.text);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
92
101
|
}
|
|
102
|
+
case 'function_definition': {
|
|
103
|
+
const name = getFuncName(node);
|
|
104
|
+
if (name) {
|
|
105
|
+
const kind = parentClassName
|
|
106
|
+
? 'method'
|
|
107
|
+
: 'function';
|
|
108
|
+
addSymbol(name, kind, node.startPosition.row + 1, node.endPosition.row + 1, parentClassName);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
case 'declaration': {
|
|
113
|
+
// Could be a function declaration (prototype) inside a class
|
|
114
|
+
if (parentClassName) {
|
|
115
|
+
const declarator = node.childForFieldName('declarator');
|
|
116
|
+
if (declarator) {
|
|
117
|
+
const funcDecl = declarator.type === 'function_declarator'
|
|
118
|
+
? declarator
|
|
119
|
+
: declarator.descendantsOfType('function_declarator')[0];
|
|
120
|
+
if (funcDecl) {
|
|
121
|
+
const nameNode = funcDecl.childForFieldName('declarator');
|
|
122
|
+
if (nameNode) {
|
|
123
|
+
addSymbol(nameNode.text, 'method', node.startPosition.row + 1, node.endPosition.row + 1, parentClassName);
|
|
124
|
+
}
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const child of node.namedChildren) {
|
|
133
|
+
walk(child, parentClassName);
|
|
93
134
|
}
|
|
94
135
|
}
|
|
136
|
+
walk(tree.rootNode);
|
|
137
|
+
tree.delete();
|
|
95
138
|
return { symbols, dependencies, relationships, warnings };
|
|
96
139
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { SymbolExtractionResult } from './ts-symbol-extractor.js';
|
|
2
|
-
export declare function extractCSharpSymbols(sourceText: string, filePath: string): SymbolExtractionResult
|
|
2
|
+
export declare function extractCSharpSymbols(sourceText: string, filePath: string): Promise<SymbolExtractionResult>;
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { parseSource } from './tree-sitter-parser.js';
|
|
2
|
+
export async function extractCSharpSymbols(sourceText, filePath) {
|
|
3
3
|
const symbols = [];
|
|
4
4
|
const dependencies = [];
|
|
5
5
|
const relationships = [];
|
|
6
6
|
const warnings = [];
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
if (!sourceText.trim()) {
|
|
8
|
+
return { symbols, dependencies, relationships, warnings };
|
|
9
|
+
}
|
|
10
|
+
const tree = await parseSource(sourceText, 'c_sharp');
|
|
11
|
+
const addSymbol = (name, kind, startLine, endLine, exported, parentName) => {
|
|
12
|
+
const id = [filePath, kind, parentName, name, startLine]
|
|
11
13
|
.filter(Boolean)
|
|
12
14
|
.join('#');
|
|
13
15
|
symbols.push({
|
|
@@ -15,8 +17,8 @@ export function extractCSharpSymbols(sourceText, filePath) {
|
|
|
15
17
|
name,
|
|
16
18
|
kind,
|
|
17
19
|
filePath,
|
|
18
|
-
startLine
|
|
19
|
-
endLine
|
|
20
|
+
startLine,
|
|
21
|
+
endLine,
|
|
20
22
|
exported,
|
|
21
23
|
parentName,
|
|
22
24
|
});
|
|
@@ -29,68 +31,92 @@ export function extractCSharpSymbols(sourceText, filePath) {
|
|
|
29
31
|
confidence: 'high',
|
|
30
32
|
});
|
|
31
33
|
};
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('*'))
|
|
37
|
-
continue;
|
|
38
|
-
braceDepth +=
|
|
39
|
-
(line.match(/\{/g) ?? []).length - (line.match(/\}/g) ?? []).length;
|
|
40
|
-
while (typeStack.length > 0 &&
|
|
41
|
-
braceDepth < typeStack[typeStack.length - 1].braceDepth) {
|
|
42
|
-
typeStack.pop();
|
|
43
|
-
}
|
|
44
|
-
// using statement
|
|
45
|
-
const usingMatch = trimmed.match(/^using\s+([\w.]+)\s*;/);
|
|
46
|
-
if (usingMatch) {
|
|
47
|
-
const specifier = usingMatch[1];
|
|
48
|
-
dependencies.push({ fromFile: filePath, specifier, kind: 'package' });
|
|
49
|
-
relationships.push({
|
|
50
|
-
sourceType: 'file',
|
|
51
|
-
sourceId: filePath,
|
|
52
|
-
targetType: 'package',
|
|
53
|
-
targetId: specifier,
|
|
54
|
-
relationshipType: 'import',
|
|
55
|
-
confidence: 'high',
|
|
56
|
-
});
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
// class / interface / struct / enum / record
|
|
60
|
-
const typeMatch = trimmed.match(/\b(?:public|private|protected|internal|static|abstract|sealed|partial|readonly)?\s*(?:public|private|protected|internal|static|abstract|sealed|partial|readonly)?\s*(?:class|interface|struct|enum|record)\s+(\w+)/);
|
|
61
|
-
if (typeMatch && typeMatch[1]) {
|
|
62
|
-
const parent = typeStack[typeStack.length - 1];
|
|
63
|
-
const exported = trimmed.includes('public') || trimmed.includes('internal');
|
|
64
|
-
addSymbol(typeMatch[1], 'class', lineNum, exported, parent?.name);
|
|
65
|
-
typeStack.push({ name: typeMatch[1], braceDepth });
|
|
66
|
-
continue;
|
|
34
|
+
function hasVisibility(node, vis) {
|
|
35
|
+
for (const child of node.children) {
|
|
36
|
+
if (child.type === 'modifier' && child.text === vis)
|
|
37
|
+
return true;
|
|
67
38
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
'
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
function isExported(node) {
|
|
42
|
+
return hasVisibility(node, 'public') || hasVisibility(node, 'internal');
|
|
43
|
+
}
|
|
44
|
+
function walk(node, parentClassName) {
|
|
45
|
+
switch (node.type) {
|
|
46
|
+
case 'using_directive': {
|
|
47
|
+
// using System; or using System.Collections.Generic;
|
|
48
|
+
const nameNode = node.namedChildren.find((c) => c.type === 'qualified_name') ??
|
|
49
|
+
node.namedChildren.find((c) => c.type === 'identifier');
|
|
50
|
+
if (nameNode) {
|
|
51
|
+
const specifier = nameNode.text;
|
|
52
|
+
dependencies.push({ fromFile: filePath, specifier, kind: 'package' });
|
|
53
|
+
relationships.push({
|
|
54
|
+
sourceType: 'file',
|
|
55
|
+
sourceId: filePath,
|
|
56
|
+
targetType: 'package',
|
|
57
|
+
targetId: specifier,
|
|
58
|
+
relationshipType: 'import',
|
|
59
|
+
confidence: 'high',
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return;
|
|
92
63
|
}
|
|
64
|
+
case 'namespace_declaration':
|
|
65
|
+
case 'file_scoped_namespace_declaration': {
|
|
66
|
+
// Recurse into namespace body
|
|
67
|
+
const body = node.childForFieldName('body') ??
|
|
68
|
+
node.namedChildren.find((c) => c.type === 'declaration_list');
|
|
69
|
+
if (body) {
|
|
70
|
+
for (const child of body.namedChildren) {
|
|
71
|
+
walk(child, parentClassName);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// file-scoped namespace: declarations are siblings
|
|
76
|
+
for (const child of node.namedChildren) {
|
|
77
|
+
walk(child, parentClassName);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
case 'class_declaration':
|
|
83
|
+
case 'interface_declaration':
|
|
84
|
+
case 'struct_declaration':
|
|
85
|
+
case 'enum_declaration':
|
|
86
|
+
case 'record_declaration': {
|
|
87
|
+
const nameNode = node.childForFieldName('name');
|
|
88
|
+
if (nameNode) {
|
|
89
|
+
const exported = isExported(node);
|
|
90
|
+
addSymbol(nameNode.text, 'class', node.startPosition.row + 1, node.endPosition.row + 1, exported, parentClassName);
|
|
91
|
+
// Walk body for methods and nested types
|
|
92
|
+
const body = node.childForFieldName('body') ??
|
|
93
|
+
node.namedChildren.find((c) => c.type === 'declaration_list');
|
|
94
|
+
if (body) {
|
|
95
|
+
for (const child of body.namedChildren) {
|
|
96
|
+
walk(child, nameNode.text);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
case 'method_declaration':
|
|
103
|
+
case 'constructor_declaration': {
|
|
104
|
+
const nameNode = node.childForFieldName('name');
|
|
105
|
+
if (nameNode) {
|
|
106
|
+
const exported = isExported(node);
|
|
107
|
+
const kind = parentClassName
|
|
108
|
+
? 'method'
|
|
109
|
+
: 'function';
|
|
110
|
+
addSymbol(nameNode.text, kind, node.startPosition.row + 1, node.endPosition.row + 1, exported, parentClassName);
|
|
111
|
+
}
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
for (const child of node.namedChildren) {
|
|
116
|
+
walk(child, parentClassName);
|
|
93
117
|
}
|
|
94
118
|
}
|
|
119
|
+
walk(tree.rootNode);
|
|
120
|
+
tree.delete();
|
|
95
121
|
return { symbols, dependencies, relationships, warnings };
|
|
96
122
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { SymbolExtractionResult } from './ts-symbol-extractor.js';
|
|
2
|
-
export declare function extractGoSymbols(sourceText: string, filePath: string): SymbolExtractionResult
|
|
2
|
+
export declare function extractGoSymbols(sourceText: string, filePath: string): Promise<SymbolExtractionResult>;
|
|
@@ -1,11 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { parseSource } from './tree-sitter-parser.js';
|
|
2
|
+
export async function extractGoSymbols(sourceText, filePath) {
|
|
3
3
|
const symbols = [];
|
|
4
4
|
const dependencies = [];
|
|
5
5
|
const relationships = [];
|
|
6
6
|
const warnings = [];
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
if (!sourceText.trim()) {
|
|
8
|
+
return { symbols, dependencies, relationships, warnings };
|
|
9
|
+
}
|
|
10
|
+
const tree = await parseSource(sourceText, 'go');
|
|
11
|
+
const addSymbol = (name, kind, startLine, endLine, parentName) => {
|
|
12
|
+
const id = [filePath, kind, parentName, name, startLine]
|
|
9
13
|
.filter(Boolean)
|
|
10
14
|
.join('#');
|
|
11
15
|
symbols.push({
|
|
@@ -13,8 +17,8 @@ export function extractGoSymbols(sourceText, filePath) {
|
|
|
13
17
|
name,
|
|
14
18
|
kind,
|
|
15
19
|
filePath,
|
|
16
|
-
startLine
|
|
17
|
-
endLine
|
|
20
|
+
startLine,
|
|
21
|
+
endLine,
|
|
18
22
|
exported: /^[A-Z]/.test(name), // Go: exported = starts with uppercase
|
|
19
23
|
parentName,
|
|
20
24
|
});
|
|
@@ -27,43 +31,12 @@ export function extractGoSymbols(sourceText, filePath) {
|
|
|
27
31
|
confidence: 'high',
|
|
28
32
|
});
|
|
29
33
|
};
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
continue;
|
|
37
|
-
// import block: import ( ... )
|
|
38
|
-
if (trimmed === 'import (') {
|
|
39
|
-
inImportBlock = true;
|
|
40
|
-
continue;
|
|
41
|
-
}
|
|
42
|
-
if (inImportBlock) {
|
|
43
|
-
if (trimmed === ')') {
|
|
44
|
-
inImportBlock = false;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
// e.g. "fmt" or aliased: log "log/slog"
|
|
48
|
-
const specMatch = trimmed.match(/"([^"]+)"/);
|
|
49
|
-
if (specMatch) {
|
|
50
|
-
const specifier = specMatch[1];
|
|
51
|
-
dependencies.push({ fromFile: filePath, specifier, kind: 'package' });
|
|
52
|
-
relationships.push({
|
|
53
|
-
sourceType: 'file',
|
|
54
|
-
sourceId: filePath,
|
|
55
|
-
targetType: 'package',
|
|
56
|
-
targetId: specifier,
|
|
57
|
-
relationshipType: 'import',
|
|
58
|
-
confidence: 'high',
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
// single import: import "fmt"
|
|
64
|
-
const singleImport = trimmed.match(/^import\s+"([^"]+)"/);
|
|
65
|
-
if (singleImport) {
|
|
66
|
-
const specifier = singleImport[1];
|
|
34
|
+
function extractImportSpec(node) {
|
|
35
|
+
// import_spec contains an interpreted_string_literal with the path
|
|
36
|
+
const pathNode = node.namedChildren.find((c) => c.type === 'interpreted_string_literal');
|
|
37
|
+
if (pathNode) {
|
|
38
|
+
// Strip quotes from the string literal
|
|
39
|
+
const specifier = pathNode.text.replace(/^"|"$/g, '');
|
|
67
40
|
dependencies.push({ fromFile: filePath, specifier, kind: 'package' });
|
|
68
41
|
relationships.push({
|
|
69
42
|
sourceType: 'file',
|
|
@@ -73,26 +46,68 @@ export function extractGoSymbols(sourceText, filePath) {
|
|
|
73
46
|
relationshipType: 'import',
|
|
74
47
|
confidence: 'high',
|
|
75
48
|
});
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
// method with receiver: func (r ReceiverType) MethodName(
|
|
79
|
-
const methodMatch = trimmed.match(/^func\s+\(\s*\w+\s+\*?(\w+)\s*\)\s+(\w+)\s*\(/);
|
|
80
|
-
if (methodMatch) {
|
|
81
|
-
addSymbol(methodMatch[2], 'method', lineNum, methodMatch[1]);
|
|
82
|
-
continue;
|
|
83
49
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
50
|
+
}
|
|
51
|
+
function walk(node) {
|
|
52
|
+
switch (node.type) {
|
|
53
|
+
case 'import_declaration': {
|
|
54
|
+
// Could contain import_spec_list or a single import_spec
|
|
55
|
+
for (const child of node.namedChildren) {
|
|
56
|
+
if (child.type === 'import_spec_list') {
|
|
57
|
+
for (const spec of child.namedChildren) {
|
|
58
|
+
if (spec.type === 'import_spec') {
|
|
59
|
+
extractImportSpec(spec);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else if (child.type === 'import_spec') {
|
|
64
|
+
extractImportSpec(child);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
case 'type_declaration': {
|
|
70
|
+
// type_declaration contains type_spec children
|
|
71
|
+
for (const child of node.namedChildren) {
|
|
72
|
+
if (child.type === 'type_spec') {
|
|
73
|
+
const nameNode = child.childForFieldName('name');
|
|
74
|
+
if (nameNode) {
|
|
75
|
+
addSymbol(nameNode.text, 'class', node.startPosition.row + 1, node.endPosition.row + 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
case 'function_declaration': {
|
|
82
|
+
const nameNode = node.childForFieldName('name');
|
|
83
|
+
if (nameNode) {
|
|
84
|
+
addSymbol(nameNode.text, 'function', node.startPosition.row + 1, node.endPosition.row + 1);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
case 'method_declaration': {
|
|
89
|
+
const nameNode = node.childForFieldName('name');
|
|
90
|
+
const receiverNode = node.childForFieldName('receiver');
|
|
91
|
+
let parentName;
|
|
92
|
+
if (receiverNode) {
|
|
93
|
+
// receiver is a parameter_list with a parameter_declaration inside
|
|
94
|
+
// that contains the type (possibly pointer_type wrapping type_identifier)
|
|
95
|
+
const typeNode = receiverNode.descendantsOfType('type_identifier')[0];
|
|
96
|
+
if (typeNode) {
|
|
97
|
+
parentName = typeNode.text;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (nameNode) {
|
|
101
|
+
addSymbol(nameNode.text, 'method', node.startPosition.row + 1, node.endPosition.row + 1, parentName);
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
89
105
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (typeMatch) {
|
|
93
|
-
addSymbol(typeMatch[1], 'class', lineNum); // 'class' is closest kind for struct/interface
|
|
94
|
-
continue;
|
|
106
|
+
for (const child of node.namedChildren) {
|
|
107
|
+
walk(child);
|
|
95
108
|
}
|
|
96
109
|
}
|
|
110
|
+
walk(tree.rootNode);
|
|
111
|
+
tree.delete();
|
|
97
112
|
return { symbols, dependencies, relationships, warnings };
|
|
98
113
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { SymbolExtractionResult } from './ts-symbol-extractor.js';
|
|
2
|
-
export declare function extractJvmSymbols(sourceText: string, filePath: string): SymbolExtractionResult
|
|
2
|
+
export declare function extractJvmSymbols(sourceText: string, filePath: string): Promise<SymbolExtractionResult>;
|