diff --git a/internal/bake/hcl/parser/schema.go b/internal/bake/hcl/parser/schema.go index 6853903..626b85c 100644 --- a/internal/bake/hcl/parser/schema.go +++ b/internal/bake/hcl/parser/schema.go @@ -198,7 +198,21 @@ var BakeSchema = &schema.BodySchema{ }, "output": { IsOptional: true, - Constraint: schema.List{Elem: schema.AnyExpression{OfType: cty.String}}, + Constraint: schema.List{Elem: schema.OneOf{ + schema.AnyExpression{OfType: cty.String}, + schema.Object{ + Attributes: map[string]*schema.AttributeSchema{ + "type": { + IsOptional: true, + Constraint: schema.AnyExpression{OfType: cty.String}, + }, + "dest": { + IsOptional: true, + Constraint: schema.AnyExpression{OfType: cty.String}, + }, + }, + }, + }}, }, "platforms": { IsOptional: true, diff --git a/internal/compose/documentLink.go b/internal/compose/documentLink.go index e053fb9..d2f13b3 100644 --- a/internal/compose/documentLink.go +++ b/internal/compose/documentLink.go @@ -7,9 +7,12 @@ import ( "path/filepath" "strings" + "log" + "github.com/docker/docker-language-server/internal/pkg/document" "github.com/docker/docker-language-server/internal/tliron/glsp/protocol" "github.com/docker/docker-language-server/internal/types" + "gopkg.in/yaml.v3" ) func DocumentLink(ctx context.Context, documentURI protocol.URI, document document.ComposeDocument) ([]protocol.DocumentLink, error) { @@ -19,16 +22,43 @@ func DocumentLink(ctx context.Context, documentURI protocol.URI, document docume } links := []protocol.DocumentLink{} - results, _ := DocumentSymbol(ctx, document) - for _, result := range results { - if symbol, ok := result.(*protocol.DocumentSymbol); ok && symbol.Kind == protocol.SymbolKindModule { - abs, err := types.AbsolutePath(url, symbol.Name) - if err == nil { - links = append(links, protocol.DocumentLink{ - Range: symbol.Range, - Target: types.CreateStringPointer(protocol.URI(fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(abs), "/")))), - Tooltip: types.CreateStringPointer(abs), - }) + rootNode := document.RootNode() + for _, serviceNode := range rootNode.Content { + if serviceNode.Kind == yaml.MappingNode { + for i := 0; i < len(serviceNode.Content); i += 2 { + keyNode := serviceNode.Content[i] + valueNode := serviceNode.Content[i+1] + if keyNode.Value == "services" && valueNode.Kind == yaml.MappingNode { + for j := 0; j < len(valueNode.Content); j += 2 { + serviceValueNode := valueNode.Content[j+1] + if serviceValueNode.Kind == yaml.MappingNode { + for k := 0; k < len(serviceValueNode.Content); k += 2 { + buildKeyNode := serviceValueNode.Content[k] + buildValueNode := serviceValueNode.Content[k+1] + if buildKeyNode.Value == "build" && buildValueNode.Kind == yaml.MappingNode { + for l := 0; l < len(buildValueNode.Content); l += 2 { + dockerfileKeyNode := buildValueNode.Content[l] + dockerfileValueNode := buildValueNode.Content[l+1] + if dockerfileKeyNode.Value == "dockerfile" { + dockerfilePath := dockerfileValueNode.Value + dockerfilePath, err = types.AbsolutePath(url, dockerfilePath) + if err == nil { + links = append(links, protocol.DocumentLink{ + Range: protocol.Range{ + Start: protocol.Position{Line: uint32(dockerfileValueNode.Line) - 1, Character: uint32(dockerfileValueNode.Column)}, + End: protocol.Position{Line: uint32(dockerfileValueNode.Line) - 1, Character: uint32(dockerfileValueNode.Column + len(dockerfilePath))}, + }, + Target: types.CreateStringPointer(protocol.URI(fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(dockerfilePath), "/")))), + Tooltip: types.CreateStringPointer(dockerfilePath), + }) + } + } + } + } + } + } + } + } } } } diff --git a/internal/compose/documentLink_test.go b/internal/compose/documentLink_test.go index 4992e85..24e1b68 100644 --- a/internal/compose/documentLink_test.go +++ b/internal/compose/documentLink_test.go @@ -41,6 +41,24 @@ func TestDocumentLink(t *testing.T) { }, }, }, + { + name: "dockerfile attribute in build section", + content: `services: + backend: + build: + context: ./backend + dockerfile: ../backend.Dockerfile`, + links: []protocol.DocumentLink{ + { + Range: protocol.Range{ + Start: protocol.Position{Line: 4, Character: 18}, + End: protocol.Position{Line: 4, Character: 38}, + }, + Target: types.CreateStringPointer(fmt.Sprintf("file:///%v", strings.TrimPrefix(filepath.ToSlash(filepath.Join(testsFolder, "../backend.Dockerfile")), "/"))), + Tooltip: types.CreateStringPointer(filepath.Join(testsFolder, "../backend.Dockerfile")), + }, + }, + }, } for _, tc := range testCases {