github.com/hashicorp/hcl/v2@v2.20.0/json/navigation.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 package json 5 6 import ( 7 "fmt" 8 "strings" 9 ) 10 11 type navigation struct { 12 root node 13 } 14 15 // Implementation of hcled.ContextString 16 func (n navigation) ContextString(offset int) string { 17 steps := navigationStepsRev(n.root, offset) 18 if steps == nil { 19 return "" 20 } 21 22 // We built our slice backwards, so we'll reverse it in-place now. 23 half := len(steps) / 2 // integer division 24 for i := 0; i < half; i++ { 25 steps[i], steps[len(steps)-1-i] = steps[len(steps)-1-i], steps[i] 26 } 27 28 ret := strings.Join(steps, "") 29 if len(ret) > 0 && ret[0] == '.' { 30 ret = ret[1:] 31 } 32 return ret 33 } 34 35 func navigationStepsRev(v node, offset int) []string { 36 switch tv := v.(type) { 37 case *objectVal: 38 // Do any of our properties have an object that contains the target 39 // offset? 40 for _, attr := range tv.Attrs { 41 k := attr.Name 42 av := attr.Value 43 44 switch av.(type) { 45 case *objectVal, *arrayVal: 46 // okay 47 default: 48 continue 49 } 50 51 if av.Range().ContainsOffset(offset) { 52 return append(navigationStepsRev(av, offset), "."+k) 53 } 54 } 55 case *arrayVal: 56 // Do any of our elements contain the target offset? 57 for i, elem := range tv.Values { 58 59 switch elem.(type) { 60 case *objectVal, *arrayVal: 61 // okay 62 default: 63 continue 64 } 65 66 if elem.Range().ContainsOffset(offset) { 67 return append(navigationStepsRev(elem, offset), fmt.Sprintf("[%d]", i)) 68 } 69 } 70 } 71 72 return nil 73 }