@@ -6,116 +6,155 @@ import (
6
6
"github.com/docker/docker-language-server/internal/pkg/document"
7
7
"github.com/docker/docker-language-server/internal/tliron/glsp/protocol"
8
8
"github.com/docker/docker-language-server/internal/types"
9
- "gopkg.in/yaml.v3"
9
+ "github.com/goccy/go-yaml/ast"
10
+ "github.com/goccy/go-yaml/token"
10
11
)
11
12
12
- func Definition (ctx context.Context , definitionLinkSupport bool , doc document.ComposeDocument , params * protocol.DefinitionParams ) (any , error ) {
13
- line := int (params .Position .Line ) + 1
14
- character := int (params .Position .Character ) + 1
15
- root := doc .RootNode ()
16
- if len (root .Content ) > 0 {
17
- for i := 0 ; i < len (root .Content [0 ].Content ); i += 2 {
18
- switch root .Content [0 ].Content [i ].Value {
19
- case "services" :
20
- for _ , service := range root .Content [0 ].Content [i + 1 ].Content {
21
- for j := 0 ; j < len (service .Content ); j += 2 {
22
- if service .Content [j ].Value == "depends_on" {
23
- if service .Content [j + 1 ].Kind == yaml .MappingNode {
24
- for k := 0 ; k < len (service .Content [j + 1 ].Content ); k += 2 {
25
- link := dependencyLink (root , definitionLinkSupport , params , service .Content [j + 1 ].Content [k ], line , character , "services" )
26
- if link != nil {
27
- return link , nil
28
- }
29
- }
30
- }
31
- if service .Content [j + 1 ].Kind == yaml .SequenceNode {
32
- for _ , dependency := range service .Content [j + 1 ].Content {
33
- link := dependencyLink (root , definitionLinkSupport , params , dependency , line , character , "services" )
34
- if link != nil {
35
- return link , nil
36
- }
37
- }
38
- }
39
- }
40
-
41
- link := lookupDependencyLink (root , definitionLinkSupport , params , service , j , line , character , "configs" )
42
- if link != nil {
43
- return link , nil
44
- }
13
+ func findSequenceDependencyToken (attributeNode * ast.MappingValueNode , attributeName string , line , column int ) (string , * token.Token ) {
14
+ if dependencies , ok := attributeNode .Value .(* ast.SequenceNode ); ok {
15
+ for _ , dependency := range dependencies .Values {
16
+ dependencyToken := dependency .GetToken ()
17
+ if dependencyToken .Position .Line == line && dependencyToken .Position .Column <= column && column <= dependencyToken .Position .Column + len (dependencyToken .Value ) {
18
+ return attributeName , dependencyToken
19
+ }
20
+ }
21
+ }
22
+ return "" , nil
23
+ }
45
24
46
- link = lookupDependencyLink (root , definitionLinkSupport , params , service , j , line , character , "networks" )
47
- if link != nil {
48
- return link , nil
49
- }
25
+ func findDependencyToken (attributeNode * ast.MappingValueNode , attributeName string , line , column int ) (string , * token.Token ) {
26
+ if attributeNode .Key .GetToken ().Value == attributeName {
27
+ return findSequenceDependencyToken (attributeNode , attributeName , line , column )
28
+ }
29
+ return "" , nil
30
+ }
50
31
51
- link = lookupDependencyLink (root , definitionLinkSupport , params , service , j , line , character , "secrets" )
52
- if link != nil {
53
- return link , nil
32
+ func lookupReference (serviceNode * ast.MappingValueNode , line , column int ) (string , * token.Token ) {
33
+ if serviceAttributes , ok := serviceNode .Value .(* ast.MappingNode ); ok {
34
+ for _ , attributeNode := range serviceAttributes .Values {
35
+ if attributeNode .Key .GetToken ().Value == "depends_on" {
36
+ if _ , ok := attributeNode .Value .(* ast.SequenceNode ); ok {
37
+ reference , dependency := findSequenceDependencyToken (attributeNode , "services" , line , column )
38
+ if dependency != nil {
39
+ return reference , dependency
40
+ }
41
+ } else if serviceAttributes , ok := attributeNode .Value .(* ast.MappingNode ); ok {
42
+ for _ , dependency := range serviceAttributes .Values {
43
+ dependencyToken := dependency .Key .GetToken ()
44
+ if dependencyToken .Position .Line == line && dependencyToken .Position .Column <= column && column <= dependencyToken .Position .Column + len (dependencyToken .Value ) {
45
+ return "services" , dependencyToken
54
46
}
55
47
}
56
48
}
57
49
}
50
+
51
+ reference , dependency := findDependencyToken (attributeNode , "configs" , line , column )
52
+ if dependency != nil {
53
+ return reference , dependency
54
+ }
55
+ reference , dependency = findDependencyToken (attributeNode , "networks" , line , column )
56
+ if dependency != nil {
57
+ return reference , dependency
58
+ }
59
+ reference , dependency = findDependencyToken (attributeNode , "secrets" , line , column )
60
+ if dependency != nil {
61
+ return reference , dependency
62
+ }
58
63
}
59
64
}
60
- return nil , nil
65
+ return "" , nil
61
66
}
62
67
63
- func lookupDependencyLink (root yaml.Node , definitionLinkSupport bool , params * protocol.DefinitionParams , service * yaml.Node , index , line , character int , nodeName string ) any {
64
- if service .Content [index ].Value == nodeName && service .Content [index + 1 ].Kind == yaml .SequenceNode {
65
- for _ , dependency := range service .Content [index + 1 ].Content {
66
- link := dependencyLink (root , definitionLinkSupport , params , dependency , line , character , nodeName )
67
- if link != nil {
68
- return link
68
+ func lookupDependency (node * ast.MappingValueNode , line , column int ) (string , * token.Token ) {
69
+ if s , ok := node .Key .(* ast.StringNode ); ok && s .Value == "services" {
70
+ if servicesNode , ok := node .Value .(* ast.MappingNode ); ok {
71
+ for _ , serviceNode := range servicesNode .Values {
72
+ reference , dependency := lookupReference (serviceNode , line , column )
73
+ if dependency != nil {
74
+ return reference , dependency
75
+ }
69
76
}
77
+ } else if valueNode , ok := node .Value .(* ast.MappingValueNode ); ok {
78
+ return lookupReference (valueNode , line , column )
70
79
}
71
80
}
72
- return nil
81
+ return "" , nil
73
82
}
74
83
75
- func dependencyLink (root yaml.Node , definitionLinkSupport bool , params * protocol.DefinitionParams , dependency * yaml.Node , line , character int , nodeName string ) any {
76
- if dependency .Line == line && dependency .Column <= character && character <= dependency .Column + len (dependency .Value ) {
77
- serviceRange := serviceDefinitionRange (root , nodeName , dependency .Value )
78
- if serviceRange == nil {
79
- return nil
84
+ func findDefinition (node * ast.MappingValueNode , referenceType , referenceName string ) * token.Token {
85
+ if s , ok := node .Key .(* ast.StringNode ); ok && s .Value == referenceType {
86
+ if servicesNode , ok := node .Value .(* ast.MappingNode ); ok {
87
+ for _ , serviceNode := range servicesNode .Values {
88
+ if serviceNode .Key .GetToken ().Value == referenceName {
89
+ return serviceNode .Key .GetToken ()
90
+ }
91
+ }
92
+ } else if networks , ok := node .Value .(* ast.MappingValueNode ); ok {
93
+ if networks .Key .GetToken ().Value == referenceName {
94
+ return networks .Key .GetToken ()
95
+ }
80
96
}
81
-
82
- return types .CreateDefinitionResult (
83
- definitionLinkSupport ,
84
- * serviceRange ,
85
- & protocol.Range {
86
- Start : protocol.Position {
87
- Line : params .Position .Line ,
88
- Character : protocol .UInteger (dependency .Column - 1 ),
89
- },
90
- End : protocol.Position {
91
- Line : params .Position .Line ,
92
- Character : protocol .UInteger (dependency .Column + len (dependency .Value ) - 1 ),
93
- },
94
- },
95
- params .TextDocument .URI ,
96
- )
97
97
}
98
98
return nil
99
99
}
100
100
101
- func serviceDefinitionRange (root yaml.Node , nodeName , serviceName string ) * protocol.Range {
102
- for i := 0 ; i < len (root .Content [0 ].Content ); i += 2 {
103
- if root .Content [0 ].Content [i ].Value == nodeName {
104
- for _ , service := range root .Content [0 ].Content [i + 1 ].Content {
105
- if service .Value == serviceName {
106
- return & protocol.Range {
107
- Start : protocol.Position {
108
- Line : protocol .UInteger (service .Line ) - 1 ,
109
- Character : protocol .UInteger (service .Column - 1 ),
110
- },
111
- End : protocol.Position {
112
- Line : protocol .UInteger (service .Line ) - 1 ,
113
- Character : protocol .UInteger (service .Column + len (serviceName ) - 1 ),
114
- },
101
+ func Definition (ctx context.Context , definitionLinkSupport bool , doc document.ComposeDocument , params * protocol.DefinitionParams ) (any , error ) {
102
+ line := int (params .Position .Line ) + 1
103
+ character := int (params .Position .Character ) + 1
104
+
105
+ file := doc .File ()
106
+ if file == nil || len (file .Docs ) == 0 {
107
+ return nil , nil
108
+ }
109
+
110
+ if mappingNode , ok := file .Docs [0 ].Body .(* ast.MappingNode ); ok {
111
+ for _ , node := range mappingNode .Values {
112
+ reference , dependency := lookupDependency (node , line , character )
113
+ if dependency != nil {
114
+ for _ , node := range mappingNode .Values {
115
+ referenced := findDefinition (node , reference , dependency .Value )
116
+ if referenced != nil {
117
+ return dependencyLink (definitionLinkSupport , params , referenced , dependency ), nil
115
118
}
116
119
}
120
+ return nil , nil
121
+ }
122
+ }
123
+ } else if mappingNodeValue , ok := file .Docs [0 ].Body .(* ast.MappingValueNode ); ok {
124
+ reference , dependency := lookupDependency (mappingNodeValue , line , character )
125
+ if dependency != nil {
126
+ referenced := findDefinition (mappingNodeValue , reference , dependency .Value )
127
+ if referenced != nil {
128
+ return dependencyLink (definitionLinkSupport , params , referenced , dependency ), nil
117
129
}
118
130
}
119
131
}
120
- return nil
132
+ return nil , nil
133
+ }
134
+
135
+ func dependencyLink (definitionLinkSupport bool , params * protocol.DefinitionParams , referenced , dependency * token.Token ) any {
136
+ return types .CreateDefinitionResult (
137
+ definitionLinkSupport ,
138
+ protocol.Range {
139
+ Start : protocol.Position {
140
+ Line : protocol .UInteger (referenced .Position .Line - 1 ),
141
+ Character : protocol .UInteger (referenced .Position .Column - 1 ),
142
+ },
143
+ End : protocol.Position {
144
+ Line : protocol .UInteger (referenced .Position .Line - 1 ),
145
+ Character : protocol .UInteger (referenced .Position .Column + len (referenced .Value ) - 1 ),
146
+ },
147
+ },
148
+ & protocol.Range {
149
+ Start : protocol.Position {
150
+ Line : params .Position .Line ,
151
+ Character : protocol .UInteger (dependency .Position .Column - 1 ),
152
+ },
153
+ End : protocol.Position {
154
+ Line : params .Position .Line ,
155
+ Character : protocol .UInteger (dependency .Position .Column + len (dependency .Value ) - 1 ),
156
+ },
157
+ },
158
+ params .TextDocument .URI ,
159
+ )
121
160
}
0 commit comments