summaryrefslogtreecommitdiff
path: root/vendor/github.com/xeipuuv/gojsonpointer/pointer.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/xeipuuv/gojsonpointer/pointer.go')
-rw-r--r--vendor/github.com/xeipuuv/gojsonpointer/pointer.go190
1 files changed, 190 insertions, 0 deletions
diff --git a/vendor/github.com/xeipuuv/gojsonpointer/pointer.go b/vendor/github.com/xeipuuv/gojsonpointer/pointer.go
new file mode 100644
index 000000000..06f1918e8
--- /dev/null
+++ b/vendor/github.com/xeipuuv/gojsonpointer/pointer.go
@@ -0,0 +1,190 @@
+// Copyright 2015 xeipuuv ( https://github.com/xeipuuv )
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// author xeipuuv
+// author-github https://github.com/xeipuuv
+// author-mail xeipuuv@gmail.com
+//
+// repository-name gojsonpointer
+// repository-desc An implementation of JSON Pointer - Go language
+//
+// description Main and unique file.
+//
+// created 25-02-2013
+
+package gojsonpointer
+
+import (
+ "errors"
+ "fmt"
+ "reflect"
+ "strconv"
+ "strings"
+)
+
+const (
+ const_empty_pointer = ``
+ const_pointer_separator = `/`
+
+ const_invalid_start = `JSON pointer must be empty or start with a "` + const_pointer_separator + `"`
+)
+
+type implStruct struct {
+ mode string // "SET" or "GET"
+
+ inDocument interface{}
+
+ setInValue interface{}
+
+ getOutNode interface{}
+ getOutKind reflect.Kind
+ outError error
+}
+
+type JsonPointer struct {
+ referenceTokens []string
+}
+
+// NewJsonPointer parses the given string JSON pointer and returns an object
+func NewJsonPointer(jsonPointerString string) (p JsonPointer, err error) {
+
+ // Pointer to the root of the document
+ if len(jsonPointerString) == 0 {
+ // Keep referenceTokens nil
+ return
+ }
+ if jsonPointerString[0] != '/' {
+ return p, errors.New(const_invalid_start)
+ }
+
+ p.referenceTokens = strings.Split(jsonPointerString[1:], const_pointer_separator)
+ return
+}
+
+// Uses the pointer to retrieve a value from a JSON document
+func (p *JsonPointer) Get(document interface{}) (interface{}, reflect.Kind, error) {
+
+ is := &implStruct{mode: "GET", inDocument: document}
+ p.implementation(is)
+ return is.getOutNode, is.getOutKind, is.outError
+
+}
+
+// Uses the pointer to update a value from a JSON document
+func (p *JsonPointer) Set(document interface{}, value interface{}) (interface{}, error) {
+
+ is := &implStruct{mode: "SET", inDocument: document, setInValue: value}
+ p.implementation(is)
+ return document, is.outError
+
+}
+
+// Both Get and Set functions use the same implementation to avoid code duplication
+func (p *JsonPointer) implementation(i *implStruct) {
+
+ kind := reflect.Invalid
+
+ // Full document when empty
+ if len(p.referenceTokens) == 0 {
+ i.getOutNode = i.inDocument
+ i.outError = nil
+ i.getOutKind = kind
+ i.outError = nil
+ return
+ }
+
+ node := i.inDocument
+
+ for ti, token := range p.referenceTokens {
+
+ isLastToken := ti == len(p.referenceTokens)-1
+
+ switch v := node.(type) {
+
+ case map[string]interface{}:
+ decodedToken := decodeReferenceToken(token)
+ if _, ok := v[decodedToken]; ok {
+ node = v[decodedToken]
+ if isLastToken && i.mode == "SET" {
+ v[decodedToken] = i.setInValue
+ }
+ } else {
+ i.outError = fmt.Errorf("Object has no key '%s'", decodedToken)
+ i.getOutKind = reflect.Map
+ i.getOutNode = nil
+ return
+ }
+
+ case []interface{}:
+ tokenIndex, err := strconv.Atoi(token)
+ if err != nil {
+ i.outError = fmt.Errorf("Invalid array index '%s'", token)
+ i.getOutKind = reflect.Slice
+ i.getOutNode = nil
+ return
+ }
+ if tokenIndex < 0 || tokenIndex >= len(v) {
+ i.outError = fmt.Errorf("Out of bound array[0,%d] index '%d'", len(v), tokenIndex)
+ i.getOutKind = reflect.Slice
+ i.getOutNode = nil
+ return
+ }
+
+ node = v[tokenIndex]
+ if isLastToken && i.mode == "SET" {
+ v[tokenIndex] = i.setInValue
+ }
+
+ default:
+ i.outError = fmt.Errorf("Invalid token reference '%s'", token)
+ i.getOutKind = reflect.ValueOf(node).Kind()
+ i.getOutNode = nil
+ return
+ }
+
+ }
+
+ i.getOutNode = node
+ i.getOutKind = reflect.ValueOf(node).Kind()
+ i.outError = nil
+}
+
+// Pointer to string representation function
+func (p *JsonPointer) String() string {
+
+ if len(p.referenceTokens) == 0 {
+ return const_empty_pointer
+ }
+
+ pointerString := const_pointer_separator + strings.Join(p.referenceTokens, const_pointer_separator)
+
+ return pointerString
+}
+
+// Specific JSON pointer encoding here
+// ~0 => ~
+// ~1 => /
+// ... and vice versa
+
+func decodeReferenceToken(token string) string {
+ step1 := strings.Replace(token, `~1`, `/`, -1)
+ step2 := strings.Replace(step1, `~0`, `~`, -1)
+ return step2
+}
+
+func encodeReferenceToken(token string) string {
+ step1 := strings.Replace(token, `~`, `~0`, -1)
+ step2 := strings.Replace(step1, `/`, `~1`, -1)
+ return step2
+}