Skip to content

Commit 83f7ae2

Browse files
committed
Begin refactoring go-yaml/yaml to goccy/go-yaml
As go-yaml/yaml has been archived, we should slowly replace our usages to goccy/go-yaml where possible. Signed-off-by: Remy Suen <[email protected]>
1 parent ced8cf5 commit 83f7ae2

File tree

5 files changed

+431
-147
lines changed

5 files changed

+431
-147
lines changed

internal/compose/definition.go

Lines changed: 124 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -6,116 +6,155 @@ import (
66
"github.com/docker/docker-language-server/internal/pkg/document"
77
"github.com/docker/docker-language-server/internal/tliron/glsp/protocol"
88
"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"
1011
)
1112

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+
}
4524

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+
}
5031

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
5446
}
5547
}
5648
}
5749
}
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+
}
5863
}
5964
}
60-
return nil, nil
65+
return "", nil
6166
}
6267

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+
}
6976
}
77+
} else if valueNode, ok := node.Value.(*ast.MappingValueNode); ok {
78+
return lookupReference(valueNode, line, column)
7079
}
7180
}
72-
return nil
81+
return "", nil
7382
}
7483

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+
}
8096
}
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-
)
9797
}
9898
return nil
9999
}
100100

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
115118
}
116119
}
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
117129
}
118130
}
119131
}
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+
)
121160
}

internal/compose/definition_test.go

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,37 +157,41 @@ services:
157157
services:
158158
test:
159159
image: alpine:3.21
160+
depends_on:
161+
- redis
160162
configs:
161-
- def
163+
- def
164+
redis:
165+
image: redis
162166
163167
configs:
164168
def:
165169
file: ./httpd.conf`,
166-
line: 5,
167-
character: 8,
170+
line: 7,
171+
character: 10,
168172
locations: []protocol.Location{
169173
{
170174
URI: composeFileURI,
171175
Range: protocol.Range{
172-
Start: protocol.Position{Line: 8, Character: 2},
173-
End: protocol.Position{Line: 8, Character: 5},
176+
Start: protocol.Position{Line: 12, Character: 2},
177+
End: protocol.Position{Line: 12, Character: 5},
174178
},
175179
},
176180
},
177181
links: []protocol.LocationLink{
178182
{
179183
OriginSelectionRange: &protocol.Range{
180-
Start: protocol.Position{Line: 5, Character: 6},
181-
End: protocol.Position{Line: 5, Character: 9},
184+
Start: protocol.Position{Line: 7, Character: 8},
185+
End: protocol.Position{Line: 7, Character: 11},
182186
},
183187
TargetURI: composeFileURI,
184188
TargetRange: protocol.Range{
185-
Start: protocol.Position{Line: 8, Character: 2},
186-
End: protocol.Position{Line: 8, Character: 5},
189+
Start: protocol.Position{Line: 12, Character: 2},
190+
End: protocol.Position{Line: 12, Character: 5},
187191
},
188192
TargetSelectionRange: protocol.Range{
189-
Start: protocol.Position{Line: 8, Character: 2},
190-
End: protocol.Position{Line: 8, Character: 5},
193+
Start: protocol.Position{Line: 12, Character: 2},
194+
End: protocol.Position{Line: 12, Character: 5},
191195
},
192196
},
193197
},

0 commit comments

Comments
 (0)