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 package jsonpointer
27
28 import (
29 "encoding/json"
30 "errors"
31 "fmt"
32 "reflect"
33 "strconv"
34 "strings"
35
36 "github.com/go-openapi/swag"
37 )
38
39 const (
40 emptyPointer = ``
41 pointerSeparator = `/`
42
43 invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
44 notFound = `Can't find the pointer in the document`
45 )
46
47 var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
48 var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
49
50
51
52 type JSONPointable interface {
53 JSONLookup(string) (any, error)
54 }
55
56
57
58 type JSONSetable interface {
59 JSONSet(string, any) error
60 }
61
62
63 func New(jsonPointerString string) (Pointer, error) {
64
65 var p Pointer
66 err := p.parse(jsonPointerString)
67 return p, err
68
69 }
70
71
72 type Pointer struct {
73 referenceTokens []string
74 }
75
76
77 func (p *Pointer) parse(jsonPointerString string) error {
78
79 var err error
80
81 if jsonPointerString != emptyPointer {
82 if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
83 err = errors.New(invalidStart)
84 } else {
85 referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
86 p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
87 }
88 }
89
90 return err
91 }
92
93
94 func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
95 return p.get(document, swag.DefaultJSONNameProvider)
96 }
97
98
99 func (p *Pointer) Set(document any, value any) (any, error) {
100 return document, p.set(document, value, swag.DefaultJSONNameProvider)
101 }
102
103
104 func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
105 return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
106 }
107
108
109 func SetForToken(document any, decodedToken string, value any) (any, error) {
110 return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
111 }
112
113 func isNil(input any) bool {
114 if input == nil {
115 return true
116 }
117
118 kind := reflect.TypeOf(input).Kind()
119 switch kind {
120 case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
121 return reflect.ValueOf(input).IsNil()
122 default:
123 return false
124 }
125 }
126
127 func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
128 rValue := reflect.Indirect(reflect.ValueOf(node))
129 kind := rValue.Kind()
130 if isNil(node) {
131 return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
132 }
133
134 switch typed := node.(type) {
135 case JSONPointable:
136 r, err := typed.JSONLookup(decodedToken)
137 if err != nil {
138 return nil, kind, err
139 }
140 return r, kind, nil
141 case *any:
142 return getSingleImpl(*typed, decodedToken, nameProvider)
143 }
144
145 switch kind {
146 case reflect.Struct:
147 nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
148 if !ok {
149 return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
150 }
151 fld := rValue.FieldByName(nm)
152 return fld.Interface(), kind, nil
153
154 case reflect.Map:
155 kv := reflect.ValueOf(decodedToken)
156 mv := rValue.MapIndex(kv)
157
158 if mv.IsValid() {
159 return mv.Interface(), kind, nil
160 }
161 return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
162
163 case reflect.Slice:
164 tokenIndex, err := strconv.Atoi(decodedToken)
165 if err != nil {
166 return nil, kind, err
167 }
168 sLength := rValue.Len()
169 if tokenIndex < 0 || tokenIndex >= sLength {
170 return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
171 }
172
173 elem := rValue.Index(tokenIndex)
174 return elem.Interface(), kind, nil
175
176 default:
177 return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
178 }
179
180 }
181
182 func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
183 rValue := reflect.Indirect(reflect.ValueOf(node))
184
185 if ns, ok := node.(JSONSetable); ok {
186 return ns.JSONSet(decodedToken, data)
187 }
188
189 if rValue.Type().Implements(jsonSetableType) {
190 return node.(JSONSetable).JSONSet(decodedToken, data)
191 }
192
193 switch rValue.Kind() {
194 case reflect.Struct:
195 nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
196 if !ok {
197 return fmt.Errorf("object has no field %q", decodedToken)
198 }
199 fld := rValue.FieldByName(nm)
200 if fld.IsValid() {
201 fld.Set(reflect.ValueOf(data))
202 }
203 return nil
204
205 case reflect.Map:
206 kv := reflect.ValueOf(decodedToken)
207 rValue.SetMapIndex(kv, reflect.ValueOf(data))
208 return nil
209
210 case reflect.Slice:
211 tokenIndex, err := strconv.Atoi(decodedToken)
212 if err != nil {
213 return err
214 }
215 sLength := rValue.Len()
216 if tokenIndex < 0 || tokenIndex >= sLength {
217 return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
218 }
219
220 elem := rValue.Index(tokenIndex)
221 if !elem.CanSet() {
222 return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
223 }
224 elem.Set(reflect.ValueOf(data))
225 return nil
226
227 default:
228 return fmt.Errorf("invalid token reference %q", decodedToken)
229 }
230
231 }
232
233 func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
234
235 if nameProvider == nil {
236 nameProvider = swag.DefaultJSONNameProvider
237 }
238
239 kind := reflect.Invalid
240
241
242 if len(p.referenceTokens) == 0 {
243 return node, kind, nil
244 }
245
246 for _, token := range p.referenceTokens {
247
248 decodedToken := Unescape(token)
249
250 r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
251 if err != nil {
252 return nil, knd, err
253 }
254 node = r
255 }
256
257 rValue := reflect.ValueOf(node)
258 kind = rValue.Kind()
259
260 return node, kind, nil
261 }
262
263 func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
264 knd := reflect.ValueOf(node).Kind()
265
266 if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
267 return errors.New("only structs, pointers, maps and slices are supported for setting values")
268 }
269
270 if nameProvider == nil {
271 nameProvider = swag.DefaultJSONNameProvider
272 }
273
274
275 if len(p.referenceTokens) == 0 {
276 return nil
277 }
278
279 lastI := len(p.referenceTokens) - 1
280 for i, token := range p.referenceTokens {
281 isLastToken := i == lastI
282 decodedToken := Unescape(token)
283
284 if isLastToken {
285
286 return setSingleImpl(node, data, decodedToken, nameProvider)
287 }
288
289 rValue := reflect.Indirect(reflect.ValueOf(node))
290 kind := rValue.Kind()
291
292 if rValue.Type().Implements(jsonPointableType) {
293 r, err := node.(JSONPointable).JSONLookup(decodedToken)
294 if err != nil {
295 return err
296 }
297 fld := reflect.ValueOf(r)
298 if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
299 node = fld.Addr().Interface()
300 continue
301 }
302 node = r
303 continue
304 }
305
306 switch kind {
307 case reflect.Struct:
308 nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
309 if !ok {
310 return fmt.Errorf("object has no field %q", decodedToken)
311 }
312 fld := rValue.FieldByName(nm)
313 if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
314 node = fld.Addr().Interface()
315 continue
316 }
317 node = fld.Interface()
318
319 case reflect.Map:
320 kv := reflect.ValueOf(decodedToken)
321 mv := rValue.MapIndex(kv)
322
323 if !mv.IsValid() {
324 return fmt.Errorf("object has no key %q", decodedToken)
325 }
326 if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
327 node = mv.Addr().Interface()
328 continue
329 }
330 node = mv.Interface()
331
332 case reflect.Slice:
333 tokenIndex, err := strconv.Atoi(decodedToken)
334 if err != nil {
335 return err
336 }
337 sLength := rValue.Len()
338 if tokenIndex < 0 || tokenIndex >= sLength {
339 return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
340 }
341
342 elem := rValue.Index(tokenIndex)
343 if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
344 node = elem.Addr().Interface()
345 continue
346 }
347 node = elem.Interface()
348
349 default:
350 return fmt.Errorf("invalid token reference %q", decodedToken)
351 }
352
353 }
354
355 return nil
356 }
357
358
359 func (p *Pointer) DecodedTokens() []string {
360 result := make([]string, 0, len(p.referenceTokens))
361 for _, t := range p.referenceTokens {
362 result = append(result, Unescape(t))
363 }
364 return result
365 }
366
367
368
369 func (p *Pointer) IsEmpty() bool {
370 return len(p.referenceTokens) == 0
371 }
372
373
374 func (p *Pointer) String() string {
375
376 if len(p.referenceTokens) == 0 {
377 return emptyPointer
378 }
379
380 pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
381
382 return pointerString
383 }
384
385 func (p *Pointer) Offset(document string) (int64, error) {
386 dec := json.NewDecoder(strings.NewReader(document))
387 var offset int64
388 for _, ttk := range p.DecodedTokens() {
389 tk, err := dec.Token()
390 if err != nil {
391 return 0, err
392 }
393 switch tk := tk.(type) {
394 case json.Delim:
395 switch tk {
396 case '{':
397 offset, err = offsetSingleObject(dec, ttk)
398 if err != nil {
399 return 0, err
400 }
401 case '[':
402 offset, err = offsetSingleArray(dec, ttk)
403 if err != nil {
404 return 0, err
405 }
406 default:
407 return 0, fmt.Errorf("invalid token %#v", tk)
408 }
409 default:
410 return 0, fmt.Errorf("invalid token %#v", tk)
411 }
412 }
413 return offset, nil
414 }
415
416 func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
417 for dec.More() {
418 offset := dec.InputOffset()
419 tk, err := dec.Token()
420 if err != nil {
421 return 0, err
422 }
423 switch tk := tk.(type) {
424 case json.Delim:
425 switch tk {
426 case '{':
427 if err = drainSingle(dec); err != nil {
428 return 0, err
429 }
430 case '[':
431 if err = drainSingle(dec); err != nil {
432 return 0, err
433 }
434 }
435 case string:
436 if tk == decodedToken {
437 return offset, nil
438 }
439 default:
440 return 0, fmt.Errorf("invalid token %#v", tk)
441 }
442 }
443 return 0, fmt.Errorf("token reference %q not found", decodedToken)
444 }
445
446 func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
447 idx, err := strconv.Atoi(decodedToken)
448 if err != nil {
449 return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err)
450 }
451 var i int
452 for i = 0; i < idx && dec.More(); i++ {
453 tk, err := dec.Token()
454 if err != nil {
455 return 0, err
456 }
457
458 if delim, isDelim := tk.(json.Delim); isDelim {
459 switch delim {
460 case '{':
461 if err = drainSingle(dec); err != nil {
462 return 0, err
463 }
464 case '[':
465 if err = drainSingle(dec); err != nil {
466 return 0, err
467 }
468 }
469 }
470 }
471
472 if !dec.More() {
473 return 0, fmt.Errorf("token reference %q not found", decodedToken)
474 }
475 return dec.InputOffset(), nil
476 }
477
478
479
480 func drainSingle(dec *json.Decoder) error {
481 for dec.More() {
482 tk, err := dec.Token()
483 if err != nil {
484 return err
485 }
486 if delim, isDelim := tk.(json.Delim); isDelim {
487 switch delim {
488 case '{':
489 if err = drainSingle(dec); err != nil {
490 return err
491 }
492 case '[':
493 if err = drainSingle(dec); err != nil {
494 return err
495 }
496 }
497 }
498 }
499
500
501 if _, err := dec.Token(); err != nil {
502 return err
503 }
504 return nil
505 }
506
507
508
509
510
511
512 const (
513 encRefTok0 = `~0`
514 encRefTok1 = `~1`
515 decRefTok0 = `~`
516 decRefTok1 = `/`
517 )
518
519
520 func Unescape(token string) string {
521 step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
522 step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
523 return step2
524 }
525
526
527 func Escape(token string) string {
528 step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
529 step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
530 return step2
531 }
532
View as plain text