forked from ebhomengo/niki
1
0
Fork 0
niki/vendor/github.com/go-openapi/jsonpointer/pointer.go

877 lines
14 KiB
Go
Raw Normal View History

2024-05-14 13:07:09 +00:00
// Copyright 2013 sigu-399 ( https://github.com/sigu-399 )
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
2024-05-14 13:07:09 +00:00
// you may not use this file except in compliance with the License.
2024-05-14 13:07:09 +00:00
// You may obtain a copy of the License at
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// Unless required by applicable law or agreed to in writing, software
2024-05-14 13:07:09 +00:00
// distributed under the License is distributed on an "AS IS" BASIS,
2024-05-14 13:07:09 +00:00
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2024-05-14 13:07:09 +00:00
// See the License for the specific language governing permissions and
2024-05-14 13:07:09 +00:00
// limitations under the License.
// author sigu-399
2024-05-14 13:07:09 +00:00
// author-github https://github.com/sigu-399
2024-05-14 13:07:09 +00:00
// author-mail sigu.399@gmail.com
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// repository-name jsonpointer
2024-05-14 13:07:09 +00:00
// repository-desc An implementation of JSON Pointer - Go language
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// description Main and unique file.
2024-05-14 13:07:09 +00:00
//
2024-05-14 13:07:09 +00:00
// created 25-02-2013
package jsonpointer
import (
"encoding/json"
"errors"
"fmt"
"reflect"
"strconv"
"strings"
"github.com/go-openapi/swag"
)
const (
emptyPointer = ``
2024-05-14 13:07:09 +00:00
pointerSeparator = `/`
invalidStart = `JSON pointer must be empty or start with a "` + pointerSeparator
notFound = `Can't find the pointer in the document`
2024-05-14 13:07:09 +00:00
)
var jsonPointableType = reflect.TypeOf(new(JSONPointable)).Elem()
2024-05-14 13:07:09 +00:00
var jsonSetableType = reflect.TypeOf(new(JSONSetable)).Elem()
// JSONPointable is an interface for structs to implement when they need to customize the
2024-05-14 13:07:09 +00:00
// json pointer process
2024-05-14 13:07:09 +00:00
type JSONPointable interface {
JSONLookup(string) (any, error)
}
// JSONSetable is an interface for structs to implement when they need to customize the
2024-05-14 13:07:09 +00:00
// json pointer process
2024-05-14 13:07:09 +00:00
type JSONSetable interface {
JSONSet(string, any) error
}
// New creates a new json pointer for the given string
2024-05-14 13:07:09 +00:00
func New(jsonPointerString string) (Pointer, error) {
var p Pointer
2024-05-14 13:07:09 +00:00
err := p.parse(jsonPointerString)
2024-05-14 13:07:09 +00:00
return p, err
}
// Pointer the json pointer reprsentation
2024-05-14 13:07:09 +00:00
type Pointer struct {
referenceTokens []string
}
// "Constructor", parses the given string JSON pointer
2024-05-14 13:07:09 +00:00
func (p *Pointer) parse(jsonPointerString string) error {
var err error
if jsonPointerString != emptyPointer {
2024-05-14 13:07:09 +00:00
if !strings.HasPrefix(jsonPointerString, pointerSeparator) {
2024-05-14 13:07:09 +00:00
err = errors.New(invalidStart)
2024-05-14 13:07:09 +00:00
} else {
2024-05-14 13:07:09 +00:00
referenceTokens := strings.Split(jsonPointerString, pointerSeparator)
2024-05-14 13:07:09 +00:00
p.referenceTokens = append(p.referenceTokens, referenceTokens[1:]...)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
return err
2024-05-14 13:07:09 +00:00
}
// Get uses the pointer to retrieve a value from a JSON document
2024-05-14 13:07:09 +00:00
func (p *Pointer) Get(document any) (any, reflect.Kind, error) {
2024-05-14 13:07:09 +00:00
return p.get(document, swag.DefaultJSONNameProvider)
2024-05-14 13:07:09 +00:00
}
// Set uses the pointer to set a value from a JSON document
2024-05-14 13:07:09 +00:00
func (p *Pointer) Set(document any, value any) (any, error) {
2024-05-14 13:07:09 +00:00
return document, p.set(document, value, swag.DefaultJSONNameProvider)
2024-05-14 13:07:09 +00:00
}
// GetForToken gets a value for a json pointer token 1 level deep
2024-05-14 13:07:09 +00:00
func GetForToken(document any, decodedToken string) (any, reflect.Kind, error) {
2024-05-14 13:07:09 +00:00
return getSingleImpl(document, decodedToken, swag.DefaultJSONNameProvider)
2024-05-14 13:07:09 +00:00
}
// SetForToken gets a value for a json pointer token 1 level deep
2024-05-14 13:07:09 +00:00
func SetForToken(document any, decodedToken string, value any) (any, error) {
2024-05-14 13:07:09 +00:00
return document, setSingleImpl(document, value, decodedToken, swag.DefaultJSONNameProvider)
2024-05-14 13:07:09 +00:00
}
func isNil(input any) bool {
2024-05-14 13:07:09 +00:00
if input == nil {
2024-05-14 13:07:09 +00:00
return true
2024-05-14 13:07:09 +00:00
}
kind := reflect.TypeOf(input).Kind()
2024-05-14 13:07:09 +00:00
switch kind { //nolint:exhaustive
2024-05-14 13:07:09 +00:00
case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
2024-05-14 13:07:09 +00:00
return reflect.ValueOf(input).IsNil()
2024-05-14 13:07:09 +00:00
default:
2024-05-14 13:07:09 +00:00
return false
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
func getSingleImpl(node any, decodedToken string, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
2024-05-14 13:07:09 +00:00
rValue := reflect.Indirect(reflect.ValueOf(node))
2024-05-14 13:07:09 +00:00
kind := rValue.Kind()
2024-05-14 13:07:09 +00:00
if isNil(node) {
2024-05-14 13:07:09 +00:00
return nil, kind, fmt.Errorf("nil value has not field %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
switch typed := node.(type) {
2024-05-14 13:07:09 +00:00
case JSONPointable:
2024-05-14 13:07:09 +00:00
r, err := typed.JSONLookup(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return nil, kind, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return r, kind, nil
2024-05-14 13:07:09 +00:00
case *any: // case of a pointer to interface, that is not resolved by reflect.Indirect
2024-05-14 13:07:09 +00:00
return getSingleImpl(*typed, decodedToken, nameProvider)
2024-05-14 13:07:09 +00:00
}
switch kind { //nolint:exhaustive
2024-05-14 13:07:09 +00:00
case reflect.Struct:
2024-05-14 13:07:09 +00:00
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
2024-05-14 13:07:09 +00:00
if !ok {
2024-05-14 13:07:09 +00:00
return nil, kind, fmt.Errorf("object has no field %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
fld := rValue.FieldByName(nm)
2024-05-14 13:07:09 +00:00
return fld.Interface(), kind, nil
case reflect.Map:
2024-05-14 13:07:09 +00:00
kv := reflect.ValueOf(decodedToken)
2024-05-14 13:07:09 +00:00
mv := rValue.MapIndex(kv)
if mv.IsValid() {
2024-05-14 13:07:09 +00:00
return mv.Interface(), kind, nil
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return nil, kind, fmt.Errorf("object has no key %q", decodedToken)
case reflect.Slice:
2024-05-14 13:07:09 +00:00
tokenIndex, err := strconv.Atoi(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return nil, kind, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
sLength := rValue.Len()
2024-05-14 13:07:09 +00:00
if tokenIndex < 0 || tokenIndex >= sLength {
2024-05-14 13:07:09 +00:00
return nil, kind, fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength-1, tokenIndex)
2024-05-14 13:07:09 +00:00
}
elem := rValue.Index(tokenIndex)
2024-05-14 13:07:09 +00:00
return elem.Interface(), kind, nil
default:
2024-05-14 13:07:09 +00:00
return nil, kind, fmt.Errorf("invalid token reference %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
}
func setSingleImpl(node, data any, decodedToken string, nameProvider *swag.NameProvider) error {
2024-05-14 13:07:09 +00:00
rValue := reflect.Indirect(reflect.ValueOf(node))
if ns, ok := node.(JSONSetable); ok { // pointer impl
2024-05-14 13:07:09 +00:00
return ns.JSONSet(decodedToken, data)
2024-05-14 13:07:09 +00:00
}
if rValue.Type().Implements(jsonSetableType) {
2024-05-14 13:07:09 +00:00
return node.(JSONSetable).JSONSet(decodedToken, data)
2024-05-14 13:07:09 +00:00
}
switch rValue.Kind() { //nolint:exhaustive
2024-05-14 13:07:09 +00:00
case reflect.Struct:
2024-05-14 13:07:09 +00:00
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
2024-05-14 13:07:09 +00:00
if !ok {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("object has no field %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
fld := rValue.FieldByName(nm)
2024-05-14 13:07:09 +00:00
if fld.IsValid() {
2024-05-14 13:07:09 +00:00
fld.Set(reflect.ValueOf(data))
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return nil
case reflect.Map:
2024-05-14 13:07:09 +00:00
kv := reflect.ValueOf(decodedToken)
2024-05-14 13:07:09 +00:00
rValue.SetMapIndex(kv, reflect.ValueOf(data))
2024-05-14 13:07:09 +00:00
return nil
case reflect.Slice:
2024-05-14 13:07:09 +00:00
tokenIndex, err := strconv.Atoi(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
sLength := rValue.Len()
2024-05-14 13:07:09 +00:00
if tokenIndex < 0 || tokenIndex >= sLength {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
2024-05-14 13:07:09 +00:00
}
elem := rValue.Index(tokenIndex)
2024-05-14 13:07:09 +00:00
if !elem.CanSet() {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("can't set slice index %s to %v", decodedToken, data)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
elem.Set(reflect.ValueOf(data))
2024-05-14 13:07:09 +00:00
return nil
default:
2024-05-14 13:07:09 +00:00
return fmt.Errorf("invalid token reference %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
}
func (p *Pointer) get(node any, nameProvider *swag.NameProvider) (any, reflect.Kind, error) {
if nameProvider == nil {
2024-05-14 13:07:09 +00:00
nameProvider = swag.DefaultJSONNameProvider
2024-05-14 13:07:09 +00:00
}
kind := reflect.Invalid
// Full document when empty
2024-05-14 13:07:09 +00:00
if len(p.referenceTokens) == 0 {
2024-05-14 13:07:09 +00:00
return node, kind, nil
2024-05-14 13:07:09 +00:00
}
for _, token := range p.referenceTokens {
decodedToken := Unescape(token)
r, knd, err := getSingleImpl(node, decodedToken, nameProvider)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return nil, knd, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
node = r
2024-05-14 13:07:09 +00:00
}
rValue := reflect.ValueOf(node)
2024-05-14 13:07:09 +00:00
kind = rValue.Kind()
return node, kind, nil
2024-05-14 13:07:09 +00:00
}
func (p *Pointer) set(node, data any, nameProvider *swag.NameProvider) error {
2024-05-14 13:07:09 +00:00
knd := reflect.ValueOf(node).Kind()
if knd != reflect.Ptr && knd != reflect.Struct && knd != reflect.Map && knd != reflect.Slice && knd != reflect.Array {
2024-05-14 13:07:09 +00:00
return errors.New("only structs, pointers, maps and slices are supported for setting values")
2024-05-14 13:07:09 +00:00
}
if nameProvider == nil {
2024-05-14 13:07:09 +00:00
nameProvider = swag.DefaultJSONNameProvider
2024-05-14 13:07:09 +00:00
}
// Full document when empty
2024-05-14 13:07:09 +00:00
if len(p.referenceTokens) == 0 {
2024-05-14 13:07:09 +00:00
return nil
2024-05-14 13:07:09 +00:00
}
lastI := len(p.referenceTokens) - 1
2024-05-14 13:07:09 +00:00
for i, token := range p.referenceTokens {
2024-05-14 13:07:09 +00:00
isLastToken := i == lastI
2024-05-14 13:07:09 +00:00
decodedToken := Unescape(token)
if isLastToken {
return setSingleImpl(node, data, decodedToken, nameProvider)
2024-05-14 13:07:09 +00:00
}
rValue := reflect.Indirect(reflect.ValueOf(node))
2024-05-14 13:07:09 +00:00
kind := rValue.Kind()
if rValue.Type().Implements(jsonPointableType) {
2024-05-14 13:07:09 +00:00
r, err := node.(JSONPointable).JSONLookup(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
fld := reflect.ValueOf(r)
2024-05-14 13:07:09 +00:00
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
2024-05-14 13:07:09 +00:00
node = fld.Addr().Interface()
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
node = r
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
switch kind { //nolint:exhaustive
2024-05-14 13:07:09 +00:00
case reflect.Struct:
2024-05-14 13:07:09 +00:00
nm, ok := nameProvider.GetGoNameForType(rValue.Type(), decodedToken)
2024-05-14 13:07:09 +00:00
if !ok {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("object has no field %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
fld := rValue.FieldByName(nm)
2024-05-14 13:07:09 +00:00
if fld.CanAddr() && fld.Kind() != reflect.Interface && fld.Kind() != reflect.Map && fld.Kind() != reflect.Slice && fld.Kind() != reflect.Ptr {
2024-05-14 13:07:09 +00:00
node = fld.Addr().Interface()
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
node = fld.Interface()
case reflect.Map:
2024-05-14 13:07:09 +00:00
kv := reflect.ValueOf(decodedToken)
2024-05-14 13:07:09 +00:00
mv := rValue.MapIndex(kv)
if !mv.IsValid() {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("object has no key %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
if mv.CanAddr() && mv.Kind() != reflect.Interface && mv.Kind() != reflect.Map && mv.Kind() != reflect.Slice && mv.Kind() != reflect.Ptr {
2024-05-14 13:07:09 +00:00
node = mv.Addr().Interface()
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
node = mv.Interface()
case reflect.Slice:
2024-05-14 13:07:09 +00:00
tokenIndex, err := strconv.Atoi(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
sLength := rValue.Len()
2024-05-14 13:07:09 +00:00
if tokenIndex < 0 || tokenIndex >= sLength {
2024-05-14 13:07:09 +00:00
return fmt.Errorf("index out of bounds array[0,%d] index '%d'", sLength, tokenIndex)
2024-05-14 13:07:09 +00:00
}
elem := rValue.Index(tokenIndex)
2024-05-14 13:07:09 +00:00
if elem.CanAddr() && elem.Kind() != reflect.Interface && elem.Kind() != reflect.Map && elem.Kind() != reflect.Slice && elem.Kind() != reflect.Ptr {
2024-05-14 13:07:09 +00:00
node = elem.Addr().Interface()
2024-05-14 13:07:09 +00:00
continue
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
node = elem.Interface()
default:
2024-05-14 13:07:09 +00:00
return fmt.Errorf("invalid token reference %q", decodedToken)
2024-05-14 13:07:09 +00:00
}
}
return nil
2024-05-14 13:07:09 +00:00
}
// DecodedTokens returns the decoded tokens
2024-05-14 13:07:09 +00:00
func (p *Pointer) DecodedTokens() []string {
2024-05-14 13:07:09 +00:00
result := make([]string, 0, len(p.referenceTokens))
2024-05-14 13:07:09 +00:00
for _, t := range p.referenceTokens {
2024-05-14 13:07:09 +00:00
result = append(result, Unescape(t))
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return result
2024-05-14 13:07:09 +00:00
}
// IsEmpty returns true if this is an empty json pointer
2024-05-14 13:07:09 +00:00
// this indicates that it points to the root document
2024-05-14 13:07:09 +00:00
func (p *Pointer) IsEmpty() bool {
2024-05-14 13:07:09 +00:00
return len(p.referenceTokens) == 0
2024-05-14 13:07:09 +00:00
}
// Pointer to string representation function
2024-05-14 13:07:09 +00:00
func (p *Pointer) String() string {
if len(p.referenceTokens) == 0 {
2024-05-14 13:07:09 +00:00
return emptyPointer
2024-05-14 13:07:09 +00:00
}
pointerString := pointerSeparator + strings.Join(p.referenceTokens, pointerSeparator)
return pointerString
2024-05-14 13:07:09 +00:00
}
func (p *Pointer) Offset(document string) (int64, error) {
2024-05-14 13:07:09 +00:00
dec := json.NewDecoder(strings.NewReader(document))
2024-05-14 13:07:09 +00:00
var offset int64
2024-05-14 13:07:09 +00:00
for _, ttk := range p.DecodedTokens() {
2024-05-14 13:07:09 +00:00
tk, err := dec.Token()
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
switch tk := tk.(type) {
2024-05-14 13:07:09 +00:00
case json.Delim:
2024-05-14 13:07:09 +00:00
switch tk {
2024-05-14 13:07:09 +00:00
case '{':
2024-05-14 13:07:09 +00:00
offset, err = offsetSingleObject(dec, ttk)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
case '[':
2024-05-14 13:07:09 +00:00
offset, err = offsetSingleArray(dec, ttk)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
default:
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("invalid token %#v", tk)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
default:
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("invalid token %#v", tk)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return offset, nil
2024-05-14 13:07:09 +00:00
}
func offsetSingleObject(dec *json.Decoder, decodedToken string) (int64, error) {
2024-05-14 13:07:09 +00:00
for dec.More() {
2024-05-14 13:07:09 +00:00
offset := dec.InputOffset()
2024-05-14 13:07:09 +00:00
tk, err := dec.Token()
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
switch tk := tk.(type) {
2024-05-14 13:07:09 +00:00
case json.Delim:
2024-05-14 13:07:09 +00:00
switch tk {
2024-05-14 13:07:09 +00:00
case '{':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
case '[':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
case string:
2024-05-14 13:07:09 +00:00
if tk == decodedToken {
2024-05-14 13:07:09 +00:00
return offset, nil
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
default:
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("invalid token %#v", tk)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("token reference %q not found", decodedToken)
2024-05-14 13:07:09 +00:00
}
func offsetSingleArray(dec *json.Decoder, decodedToken string) (int64, error) {
2024-05-14 13:07:09 +00:00
idx, err := strconv.Atoi(decodedToken)
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("token reference %q is not a number: %v", decodedToken, err)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
var i int
2024-05-14 13:07:09 +00:00
for i = 0; i < idx && dec.More(); i++ {
2024-05-14 13:07:09 +00:00
tk, err := dec.Token()
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
if delim, isDelim := tk.(json.Delim); isDelim {
2024-05-14 13:07:09 +00:00
switch delim {
2024-05-14 13:07:09 +00:00
case '{':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
case '[':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return 0, err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
if !dec.More() {
2024-05-14 13:07:09 +00:00
return 0, fmt.Errorf("token reference %q not found", decodedToken)
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return dec.InputOffset(), nil
2024-05-14 13:07:09 +00:00
}
// drainSingle drains a single level of object or array.
2024-05-14 13:07:09 +00:00
// The decoder has to guarantee the beginning delim (i.e. '{' or '[') has been consumed.
2024-05-14 13:07:09 +00:00
func drainSingle(dec *json.Decoder) error {
2024-05-14 13:07:09 +00:00
for dec.More() {
2024-05-14 13:07:09 +00:00
tk, err := dec.Token()
2024-05-14 13:07:09 +00:00
if err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
if delim, isDelim := tk.(json.Delim); isDelim {
2024-05-14 13:07:09 +00:00
switch delim {
2024-05-14 13:07:09 +00:00
case '{':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
case '[':
2024-05-14 13:07:09 +00:00
if err = drainSingle(dec); err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
}
// Consumes the ending delim
2024-05-14 13:07:09 +00:00
if _, err := dec.Token(); err != nil {
2024-05-14 13:07:09 +00:00
return err
2024-05-14 13:07:09 +00:00
}
2024-05-14 13:07:09 +00:00
return nil
2024-05-14 13:07:09 +00:00
}
// Specific JSON pointer encoding here
2024-05-14 13:07:09 +00:00
// ~0 => ~
2024-05-14 13:07:09 +00:00
// ~1 => /
2024-05-14 13:07:09 +00:00
// ... and vice versa
const (
encRefTok0 = `~0`
2024-05-14 13:07:09 +00:00
encRefTok1 = `~1`
2024-05-14 13:07:09 +00:00
decRefTok0 = `~`
2024-05-14 13:07:09 +00:00
decRefTok1 = `/`
)
// Unescape unescapes a json pointer reference token string to the original representation
2024-05-14 13:07:09 +00:00
func Unescape(token string) string {
2024-05-14 13:07:09 +00:00
step1 := strings.ReplaceAll(token, encRefTok1, decRefTok1)
2024-05-14 13:07:09 +00:00
step2 := strings.ReplaceAll(step1, encRefTok0, decRefTok0)
2024-05-14 13:07:09 +00:00
return step2
2024-05-14 13:07:09 +00:00
}
// Escape escapes a pointer reference token string
2024-05-14 13:07:09 +00:00
func Escape(token string) string {
2024-05-14 13:07:09 +00:00
step1 := strings.ReplaceAll(token, decRefTok0, encRefTok0)
2024-05-14 13:07:09 +00:00
step2 := strings.ReplaceAll(step1, decRefTok1, encRefTok1)
2024-05-14 13:07:09 +00:00
return step2
2024-05-14 13:07:09 +00:00
}