diff --git a/zcl/json/navigation.go b/zcl/json/navigation.go new file mode 100644 index 0000000..d28e603 --- /dev/null +++ b/zcl/json/navigation.go @@ -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 +} diff --git a/zcl/json/navigation_test.go b/zcl/json/navigation_test.go new file mode 100644 index 0000000..c2e89e0 --- /dev/null +++ b/zcl/json/navigation_test.go @@ -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) + } + }) + } +} diff --git a/zcl/json/public.go b/zcl/json/public.go index 5d20467..09b17b2 100644 --- a/zcl/json/public.go +++ b/zcl/json/public.go @@ -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