Skip to content

Commit

Permalink
fix: handle root variable ($) at different stage
Browse files Browse the repository at this point in the history
  • Loading branch information
qvalentin committed May 20, 2024
1 parent da5d643 commit a26b767
Show file tree
Hide file tree
Showing 7 changed files with 66 additions and 18 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ test:
@$(GO) test ./... -v -race -tags=integration

coverage:
@$(GO) test -coverprofile=.coverage -tags=integration ./internal/... && go tool cover -html=.coverage
@$(GO) test -coverprofile=.coverage -tags=integration -coverpkg=./internal/... ./internal/... && go tool cover -html=.coverage

.PHONY: build-release
build-release:
Expand Down
7 changes: 6 additions & 1 deletion internal/lsp/symbol_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ func NewSymbolTable(ast *sitter.Tree, content []byte) *SymbolTable {
}

func (s *SymbolTable) AddTemplateContext(templateContext TemplateContext, pointRange sitter.Range) {
s.contexts[templateContext.Format()] = append(s.contexts[strings.Join(templateContext, ".")], pointRange)
if templateContext.IsVariable() && templateContext[0] == "$" {
// $ is a special variable that resolves to the root context
// we can just remove it from the template context
templateContext = templateContext.Tail()
}
s.contexts[templateContext.Format()] = append(s.contexts[templateContext.Format()], pointRange)
sliceCopy := make(TemplateContext, len(templateContext))
copy(sliceCopy, templateContext)
s.contextsReversed[pointRange] = sliceCopy
Expand Down
15 changes: 4 additions & 11 deletions internal/lsp/symbol_table_template_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) {
v.symbolTable.AddTemplateContext(append(v.currentContext, content), GetRangeForNode(node.ChildByFieldName("name")))
case gotemplate.NodeTypeUnfinishedSelectorExpression:
operandNode := node.ChildByFieldName("operand")
if operandNode.Type() == gotemplate.NodeTypeVariable && operandNode.Content(v.content) == "$" {
if operandNode.Type() == gotemplate.NodeTypeVariable {
v.StashContext()
}
v.symbolTable.AddTemplateContext(append(getContextForSelectorExpression(operandNode, v.content), ""),
Expand All @@ -69,10 +69,8 @@ func (v *TemplateContextVisitor) Enter(node *sitter.Node) {
operandNode := node.ChildByFieldName("operand")
if operandNode.Type() == gotemplate.NodeTypeVariable {
v.StashContext()
if operandNode.Content(v.content) != "$" {
v.symbolTable.AddTemplateContext(append(v.currentContext, operandNode.Content(v.content)), GetRangeForNode(operandNode))
v.PushContext(operandNode.Content(v.content))
}
v.symbolTable.AddTemplateContext(append(v.currentContext, operandNode.Content(v.content)), GetRangeForNode(operandNode))
v.PushContext(operandNode.Content(v.content))
}
}
}
Expand All @@ -82,9 +80,7 @@ func (v *TemplateContextVisitor) Exit(node *sitter.Node) {
case gotemplate.NodeTypeSelectorExpression, gotemplate.NodeTypeUnfinishedSelectorExpression:
operandNode := node.ChildByFieldName("operand")
if operandNode.Type() == gotemplate.NodeTypeVariable {
if operandNode.Content(v.content) != "$" {
v.PopContext()
}
v.PopContext()
v.RestoreStashedContext()
}
}
Expand All @@ -104,9 +100,6 @@ func (v *TemplateContextVisitor) EnterContextShift(node *sitter.Node, suffix str
s = s.AppendSuffix(suffix)
if s.IsVariable() {
v.StashContext()
if s[0] == "$" {
s = s.Tail()
}
}
}
v.PushContextMany(s)
Expand Down
26 changes: 25 additions & 1 deletion internal/lsp/symbol_table_template_context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,41 @@ func TestGetContextForSelectorExpression(t *testing.T) {
expected TemplateContext
}{
{
desc: "Selects single selector expression correctly",
desc: "Selects simple selector expression correctly",
template: `{{ .Values.test }}`,
nodeContent: ".Values.test",
expected: TemplateContext{"Values", "test"},
},
{
desc: "Selects unfinished selector expression correctly",
template: `{{ .Values.test. }}`,
nodeContent: ".Values.test.",
expected: TemplateContext{"Values", "test"},
},
{
desc: "Selects selector expression with $ correctly",
template: `{{ $.Values.test }}`,
nodeContent: "$.Values.test",
expected: TemplateContext{"$", "Values", "test"},
},
{
desc: "Selects unfinished selector expression with $ correctly",
template: `{{ $.Values.test. }}`,
nodeContent: "$.Values.test.",
expected: TemplateContext{"$", "Values", "test"},
},
{
desc: "Selects selector expression with variable correctly",
template: `{{ $x.test }}`,
nodeContent: "$x.test",
expected: TemplateContext{"$x", "test"},
},
{
desc: "Selects unfinished selector expression with variable correctly",
template: `{{ $x.test. }}`,
nodeContent: "$x.test.",
expected: TemplateContext{"$x", "test"},
},
}
for _, tC := range testCases {
t.Run(tC.desc, func(t *testing.T) {
Expand Down
30 changes: 27 additions & 3 deletions internal/lsp/symbol_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,9 +217,10 @@ func TestSymbolTableForValuesTestFile(t *testing.T) {

func TestSymbolTableForValuesSingleTests(t *testing.T) {
type testCase struct {
template string
path []string
startPoint sitter.Point
template string
path []string
startPoint sitter.Point
foundContextsLen int
}

testCases := []testCase{
Expand All @@ -236,6 +237,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) {
Row: 2,
Column: 40,
},
foundContextsLen: 7,
},
{
template: `{{ $x := .Values }}{{ $x.test }}{{ .Values.test }}`,
Expand All @@ -244,6 +246,25 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) {
Row: 0,
Column: 25,
},
foundContextsLen: 4,
},
{
template: `{{ $x.test }}`,
path: []string{"$x", "test"},
startPoint: sitter.Point{
Row: 0,
Column: 6,
},
foundContextsLen: 2,
},
{
template: `{{ $x.test. }}`,
path: []string{"$x", "test", ""},
startPoint: sitter.Point{
Row: 0,
Column: 10,
},
foundContextsLen: 3,
},
{
template: `{{ if (and .Values. ) }} {{ end }} `,
Expand All @@ -252,6 +273,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) {
Row: 0,
Column: 12,
},
foundContextsLen: 2,
},
{
template: `{{ if (and .Values. ) }} {{ end }} `,
Expand All @@ -260,6 +282,7 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) {
Row: 0,
Column: 18,
},
foundContextsLen: 2,
},
}

Expand All @@ -272,5 +295,6 @@ func TestSymbolTableForValuesSingleTests(t *testing.T) {
points = append(points, v.StartPoint)
}
assert.Contains(t, points, v.startPoint)
assert.Len(t, symbolTable.contexts, v.foundContextsLen)
}
}
2 changes: 2 additions & 0 deletions internal/lsp/visitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ func (v *Visitors) visitNodesRecursiveWithScopeShift(node *sitter.Node) {
case gotemplate.NodeTypeRangeAction:
rangeNode := node.ChildByFieldName("range")
if rangeNode == nil {
// for {{- range $type, $config := $root.Values.deployments }} the range node is in the
// range_variable_definition node an not in the range_action node
rangeNode = node.NamedChild(0).ChildByFieldName("range")
if rangeNode == nil {
logger.Error("Could not find range node")
Expand Down
2 changes: 1 addition & 1 deletion testdata/example/templates/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,6 @@ spec:
name: my-app-{{ $type }}
spec:
replicas: {{ $config.hpa.minReplicas }}
{{ $.Values.ingress.hosts }}
test: {{ $.Values.ingress.hosts }}
---
{{- end }}

0 comments on commit a26b767

Please sign in to comment.