-
Notifications
You must be signed in to change notification settings - Fork 38
/
imports.go
124 lines (101 loc) · 3.63 KB
/
imports.go
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package csharp
import (
"github.com/klothoplatform/klotho/pkg/core"
"github.com/klothoplatform/klotho/pkg/query"
sitter "github.com/smacker/go-tree-sitter"
)
// C# using directive spec: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/namespaces#135-using-directives
// TODO: add support for "extern alias" imports: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/extern-alias
type ImportType string
const (
ImportTypeUsing = ImportType("using")
ImportTypeUsingAlias = ImportType("using_alias")
ImportTypeUsingStatic = ImportType("using_static")
)
type ImportScope string
const (
ImportScopeGlobal = ImportScope("global")
ImportScopeCompilationUnit = ImportScope("compilation_unit")
ImportScopeNamespace = ImportScope("namespace")
)
type Import struct {
// Name is the exported name of the Import
Name string
// Node is the *sitter.Node associated with the Import's using directive
Node *sitter.Node
// Alias is the name with which this import is referred to in its enclosing Scope (i.e. module or local)
Alias string
Scope ImportScope
Type ImportType
Namespace string
}
// Imports provides a mapping between import sources and the list of imports for each.
type Imports map[string][]Import
// ImportedAs returns the name of the import as it will be used locally (either the exported name or local alias).
func (p *Import) ImportedAs() string {
if p.Alias != "" {
return p.Alias
}
return p.Name
}
// AsSlice converts an instance of Imports to []Import for simpler iteration over all Import values.
func (imports Imports) AsSlice() []Import {
var slice []Import
for _, importsOfSource := range imports {
slice = append(slice, importsOfSource...)
}
return slice
}
// FindImportsInFile returns a map containing a list of imports for each import source referenced within the file.
func FindImportsInFile(file *core.SourceFile) Imports {
return FindImportsAtNode(file.Tree().RootNode())
}
// FindImportsAtNode returns a map containing a list of imports for each import source starting from the supplied node.
func FindImportsAtNode(node *sitter.Node) Imports {
fileImports := Imports{}
matches := query.Collect(DoQuery(node, usingDirectives))
for _, match := range matches {
parsedImport := parseUsingDirective(match)
i := fileImports[parsedImport.Name]
fileImports[parsedImport.Name] = append(i, parsedImport)
}
return fileImports
}
func parseUsingDirective(match query.MatchNodes) Import {
usingDirective := match["using_directive"]
identifier := match["identifier"]
alias := match["alias"]
global := match["global"]
static := match["static"]
parsedImport := Import{
Name: identifier.Content(),
Node: usingDirective,
}
if global != nil {
parsedImport.Scope = ImportScopeGlobal
} else if isFileScoped(usingDirective) {
parsedImport.Scope = ImportScopeCompilationUnit
}
if namespace := namespaceAncestor(usingDirective); namespace != nil {
parsedImport.Scope = ImportScopeNamespace
parsedImport.Namespace = namespace.ChildByFieldName("name").Content()
}
if static != nil {
parsedImport.Type = ImportTypeUsingStatic
} else if aliasContent := query.NodeContentOrEmpty(alias); aliasContent != "" {
parsedImport.Type = ImportTypeUsingAlias
parsedImport.Alias = aliasContent
} else {
parsedImport.Type = ImportTypeUsing
}
return parsedImport
}
func isFileScoped(usingNode *sitter.Node) bool {
if usingNode == nil {
return false
}
return usingNode.Parent().Type() == "compilation_unit"
}
func namespaceAncestor(usingNode *sitter.Node) *sitter.Node {
return query.FirstAncestorOfType(usingNode, "namespace_declaration")
}