github.com/vanus-labs/vanus/lib@v0.0.0-20231221070800-1334a7b9605e/json/path/parse.go (about) 1 // Copyright 2023 Linkall Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package path 16 17 import ( 18 // standard libraries. 19 "errors" 20 "strings" 21 "unicode/utf8" 22 23 // this project. 24 "github.com/vanus-labs/vanus/lib/bytes" 25 "github.com/vanus-labs/vanus/lib/json/parse" 26 ) 27 28 var errInvalidJSONPath = errors.New("invalid JSON path") 29 30 func Parse(text string) (Path, error) { 31 s := bytes.NewMarkScanner(bytes.UnsafeFromString(text)) 32 if bytes.ExpectChar(s, '$') != nil { // root identifier 33 return nil, errInvalidJSONPath 34 } 35 segments, err := ConsumeSegments(s) 36 if err != nil { 37 return nil, errInvalidJSONPath 38 } 39 return &rootPath{segments: segments}, nil 40 } 41 42 func ConsumeExt(c byte, s *bytes.MarkScanner) (Path, error) { 43 if c != '$' { 44 return nil, errInvalidJSONPath 45 } 46 segments, err := ConsumeSegments(s) 47 if err != nil { 48 return nil, errInvalidJSONPath 49 } 50 return &rootPath{segments: segments}, nil 51 } 52 53 func ConsumeSegments(s *bytes.MarkScanner) ([]Segment, error) { 54 var segments []Segment 55 for { 56 m := s.Mark(0) 57 segment, err := consumeSegment(s) 58 if err != nil { 59 _ = s.Resume(m) 60 if len(segments) == 0 { 61 return nil, err 62 } 63 return segments, nil 64 } 65 segments = append(segments, segment) 66 } 67 } 68 69 func consumeSegment(s *bytes.MarkScanner) (Segment, error) { 70 c, err := s.ReadByte() 71 if err != nil { 72 return nil, err 73 } 74 75 switch c { 76 case '[': 77 return consumeBracketedSelection(s) 78 case '.': 79 return consumeDotSegment(s) 80 default: 81 return nil, errInvalidJSONPath 82 } 83 } 84 85 func consumeBracketedSelection(s *bytes.MarkScanner) (Segment, error) { 86 var selectors []Selector 87 for { 88 _, c, err := parse.SkipWhitespace(s) 89 if err != nil { 90 return nil, err 91 } 92 93 selector, err := consumeSelectorExt(c, s) 94 if err != nil { 95 return nil, err 96 } 97 98 selectors = append(selectors, selector) 99 100 _, c, err = parse.SkipWhitespace(s) 101 if err != nil { 102 return nil, err 103 } 104 105 switch c { 106 case ']': // end of bracketed selection 107 return &bracketedSelection{selectors: selectors}, nil 108 case ',': // continue 109 default: 110 return nil, errInvalidJSONPath 111 } 112 } 113 } 114 115 func consumeSelectorExt(c byte, s *bytes.MarkScanner) (Selector, error) { 116 switch c { 117 case '\'': // name selector 118 var b strings.Builder 119 if err := parse.ConsumeSingleQuotedString(s, &b); err != nil { 120 return nil, err 121 } 122 return &nameSelector{member: b.String()}, nil 123 case '"': // name selector 124 var b strings.Builder 125 if err := parse.ConsumeDoubleQuotedString(s, &b); err != nil { 126 return nil, err 127 } 128 return &nameSelector{member: b.String()}, nil 129 case '*': // wildcard selector 130 return &wildcardSelector{}, nil 131 case '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 132 return consumeIndexOrSliceSelector(c, s) 133 case ':': // array slice selector 134 return consumeSliceSelector(nil, s) 135 case '?': // filter selector 136 // TODO(james.yin) 137 return nil, errors.New("not implemented filter selector") 138 } 139 return nil, errInvalidJSONPath 140 } 141 142 func consumeIndexOrSliceSelector(c byte, s *bytes.MarkScanner) (Selector, error) { 143 indexOrStart, err := parse.ExpectIntegerExt(c, s) 144 if err != nil { 145 return nil, err 146 } 147 148 m := s.Mark(0) 149 if _, c, err = parse.SkipWhitespace(s); err != nil { 150 return nil, err 151 } 152 153 // array slice selector 154 if c == ':' { 155 return consumeSliceSelector(&indexOrStart, s) 156 } 157 158 _ = s.Resume(m) 159 return &indexSelector{index: indexOrStart}, nil 160 } 161 162 func consumeSliceSelector(start *int, s *bytes.MarkScanner) (*arraySliceSelector, error) { 163 m := s.Mark(0) 164 _, c, err := parse.SkipWhitespace(s) 165 if err != nil { 166 _ = s.Resume(m) 167 return nil, err 168 } 169 170 var end *int 171 172 me := s.Mark(0) 173 e, err := parse.ExpectIntegerExt(c, s) 174 if err != nil { 175 _ = s.Resume(me) 176 } else { 177 end = &e 178 m = s.Mark(0) 179 if _, c, err = parse.SkipWhitespace(s); err != nil { 180 return nil, err 181 } 182 } 183 184 step := 1 185 if c == ':' { 186 m = s.Mark(0) 187 if _, c, err = parse.SkipWhitespace(s); err != nil { 188 return nil, err 189 } 190 if step, err = parse.ExpectIntegerExt(c, s); err != nil { 191 step = 1 192 _ = s.Resume(m) 193 } 194 } else { 195 _ = s.Resume(m) 196 } 197 198 return &arraySliceSelector{ 199 start: start, 200 end: end, 201 step: step, 202 }, nil 203 } 204 205 func consumeDotSegment(s *bytes.MarkScanner) (Segment, error) { 206 r, _ := bytes.ReadRune(s) 207 switch r { 208 case '*': // wildcard selector 209 return &wildcardSelector{}, nil 210 case '.': // descendant segment 211 // TODO(james.yin) 212 return nil, errors.New("not implemented descendant segment") 213 default: // member-name-shorthand 214 return consumeMemberNameShorthandExt(r, s) 215 } 216 } 217 218 func consumeMemberNameShorthandExt(r rune, s *bytes.MarkScanner) (Segment, error) { 219 var b strings.Builder 220 221 if r == utf8.RuneError || !parse.ExceptNameFirst(r) { 222 return nil, errInvalidJSONPath 223 } 224 if _, err := b.WriteRune(r); err != nil { 225 return nil, err 226 } 227 228 for { 229 m := s.Mark(0) 230 r, _ = bytes.ReadRune(s) 231 if r == utf8.RuneError || !parse.ExceptNameChar(r) { 232 _ = s.Resume(m) 233 return &nameSelector{member: b.String()}, nil 234 } 235 if _, err := b.WriteRune(r); err != nil { 236 return nil, err 237 } 238 } 239 }