json: ContextString implementation
This JSON-flavored ContextString implementation returns a chain of property names using JavaScript-style attribute access syntax.
This commit is contained in:
parent
a940c30903
commit
d2c9089812
41
zcl/json/navigation.go
Normal file
41
zcl/json/navigation.go
Normal file
@ -0,0 +1,41 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type navigation struct {
|
||||
root *objectVal
|
||||
}
|
||||
|
||||
// Implementation of zcled.ContextString
|
||||
func (n navigation) ContextString(offset int) string {
|
||||
steps := navigationStepsRev(n.root, offset)
|
||||
if steps == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// We built our slice backwards, so we'll reverse it in-place now.
|
||||
half := len(steps) / 2 // integer division
|
||||
for i := 0; i < half; i++ {
|
||||
steps[i], steps[len(steps)-1-i] = steps[len(steps)-1-i], steps[i]
|
||||
}
|
||||
|
||||
return strings.Join(steps, ".")
|
||||
}
|
||||
|
||||
func navigationStepsRev(obj *objectVal, offset int) []string {
|
||||
// Do any of our properties have an object that contains the target
|
||||
// offset?
|
||||
for k, attr := range obj.Attrs {
|
||||
ov, ok := attr.Value.(*objectVal)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if ov.SrcRange.ContainsOffset(offset) {
|
||||
return append(navigationStepsRev(ov, offset), k)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
50
zcl/json/navigation_test.go
Normal file
50
zcl/json/navigation_test.go
Normal file
@ -0,0 +1,50 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNavigationContextString(t *testing.T) {
|
||||
src := `
|
||||
{
|
||||
"version": 1,
|
||||
"resource": {
|
||||
"null_resource": {
|
||||
"baz": {
|
||||
"id": "foo"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
file, diags := Parse([]byte(src), "test.json")
|
||||
if len(diags) != 0 {
|
||||
t.Errorf("Unexpected diagnostics: %#v", diags)
|
||||
}
|
||||
if file == nil {
|
||||
t.Fatalf("Got nil file")
|
||||
}
|
||||
nav := file.Nav.(navigation)
|
||||
|
||||
tests := []struct {
|
||||
Offset int
|
||||
Want string
|
||||
}{
|
||||
{0, ``},
|
||||
{8, ``},
|
||||
{36, `resource`},
|
||||
{60, `resource.null_resource`},
|
||||
{89, `resource.null_resource.baz`},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(strconv.Itoa(test.Offset), func(t *testing.T) {
|
||||
got := nav.ContextString(test.Offset)
|
||||
|
||||
if got != test.Want {
|
||||
t.Errorf("wrong result\ngot: %s\nwant: %s", got, test.Want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -34,6 +34,7 @@ func Parse(src []byte, filename string) (*zcl.File, zcl.Diagnostics) {
|
||||
obj: rootNode.(*objectVal),
|
||||
},
|
||||
Bytes: src,
|
||||
Nav: navigation{rootNode.(*objectVal)},
|
||||
}
|
||||
}
|
||||
return file, diags
|
||||
|
Loading…
Reference in New Issue
Block a user