1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
package segments
import "fmt"
func ParseSegment(path string) ([]YamlPathSegment, error) {
if path[0] == '/' {
return parseSegment(path[1:], '/')
}
return parseSegment(path, '.')
}
func parseSegment(path string, separator rune) ([]YamlPathSegment, error) {
segments := []YamlPathSegment{}
currentSegment := []rune{}
i := 0
for i < len(path) {
r := rune(path[i])
switch r {
case separator:
if err := addSegment(currentSegment, &segments); err != nil {
return nil, err
}
currentSegment = []rune{}
case '\\':
i++
r = rune(path[i])
currentSegment = append(currentSegment, r)
case '"', '\'':
if err := addSegment(currentSegment, &segments); err != nil {
return nil, err
}
currentSegment = []rune{}
p, endIdx, err := parsePathUntil(path, i+1, r, false) //nolint:gomnd
if err != nil {
return nil, err
}
segments = append(segments, p)
i = endIdx
case '[':
if err := addSegment(currentSegment, &segments); err != nil {
return nil, err
}
currentSegment = []rune{}
p, endIdx, err := parsePathUntil(path, i, ']', true)
if err != nil {
return nil, err
}
segments = append(segments, p)
i = endIdx
default:
currentSegment = append(currentSegment, r)
}
i++
}
if len(currentSegment) > 0 {
if err := addSegment(currentSegment, &segments); err != nil {
return nil, err
}
}
return segments, nil
}
func addSegment(segment []rune, segments *[]YamlPathSegment) error {
if len(segment) == 0 {
return nil
}
p, err := DetectSegment(string(segment))
if err != nil {
return err
}
l := append(*segments, p)
*segments = l
return nil
}
func parsePathUntil(path string, idx int, stopOn rune, inclusive bool) (YamlPathSegment, int, error) {
segment := []rune{}
i := idx
for i < len(path) {
r := rune(path[i])
segment = append(segment, r)
if r == stopOn {
if !inclusive {
segment = segment[0 : len(segment)-1]
}
ypp, err := DetectSegment(string(segment))
return ypp, i + 1, err
}
i++
}
return nil, -1, fmt.Errorf("could not find terminating '%c' in path '%s'", stopOn, path[idx:])
}
|