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),
|
obj: rootNode.(*objectVal),
|
||||||
},
|
},
|
||||||
Bytes: src,
|
Bytes: src,
|
||||||
|
Nav: navigation{rootNode.(*objectVal)},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return file, diags
|
return file, diags
|
||||||
|
Loading…
Reference in New Issue
Block a user