-
Notifications
You must be signed in to change notification settings - Fork 4.1k
Expand file tree
/
Copy pathsymbol_extraction.go
More file actions
67 lines (59 loc) · 2.07 KB
/
symbol_extraction.go
File metadata and controls
67 lines (59 loc) · 2.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package github
import (
"fmt"
"strings"
)
// ExtractSymbol searches source code for a named symbol and returns its text.
// It searches top-level declarations first, then recursively searches nested
// declarations (e.g. methods inside classes). Returns the symbol text and its
// kind, or an error if the symbol is not found or the language is unsupported.
func ExtractSymbol(path string, source []byte, symbolName string) (text string, kind string, err error) {
config := languageForPath(path)
if config == nil {
return "", "", fmt.Errorf("symbol extraction is not supported for this file type")
}
decls, err := extractDeclarations(config, source)
if err != nil {
return "", "", fmt.Errorf("failed to parse file: %w", err)
}
// Search top-level declarations
if text, kind, found := findSymbol(decls, symbolName); found {
return text, kind, nil
}
// Search nested declarations (methods inside classes, etc.)
for _, decl := range decls {
nested := extractChildDeclarationsFromText(config, decl.Text)
if text, kind, found := findSymbol(nested, symbolName); found {
return text, kind, nil
}
}
// Build list of available symbols for the error message
available := listSymbolNames(config, decls)
return "", "", fmt.Errorf("symbol %q not found. Available symbols: %s", symbolName, strings.Join(available, ", "))
}
// findSymbol searches a slice of declarations for a matching name.
func findSymbol(decls []declaration, name string) (string, string, bool) {
for _, d := range decls {
if d.Name == name {
return d.Text, d.Kind, true
}
}
return "", "", false
}
// listSymbolNames returns all symbol names from top-level and one level of
// nested declarations, for use in error messages.
func listSymbolNames(config *languageConfig, decls []declaration) []string {
var names []string
for _, d := range decls {
if !strings.HasPrefix(d.Name, "_") {
names = append(names, d.Name)
}
nested := extractChildDeclarationsFromText(config, d.Text)
for _, n := range nested {
if !strings.HasPrefix(n.Name, "_") {
names = append(names, n.Name)
}
}
}
return names
}