Skip to content

Commit 63edefd

Browse files
committed
init
0 parents  commit 63edefd

21 files changed

+2018
-0
lines changed

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
*.exe
2+
*.exe~
3+
*.dll
4+
*.so
5+
*.dylib
6+
7+
# Test binary, built with `go test -c`
8+
*.test
9+
10+
# Output of the go coverage tool, specifically when used with LiteIDE
11+
*.out
12+
13+
# Dependency directories (remove the comment below to include it)
14+
# vendor/
15+
16+
# Go workspace file
17+
go.work

.vscode/launch.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Launch Package",
9+
"type": "go",
10+
"request": "launch",
11+
"mode": "auto",
12+
"program": "${fileDirname}"
13+
}
14+
]
15+
}

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# jsonpointer
2+
3+
wip

assign.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package jsonpointer
2+
3+
import "reflect"
4+
5+
type Assigner interface {
6+
AssignByJSONPointer(ptr *JSONPointer, value interface{}) error
7+
}
8+
9+
func Assign(ptr JSONPointer, src interface{}, value interface{}) error {
10+
if err := ptr.Validate(); err != nil {
11+
return err
12+
}
13+
14+
// not sure whether or not to delete this. Leaving it out for now.
15+
//
16+
// if ptr == TopLevel {
17+
// return &ptrError{
18+
// err: ErrEmptyJSONPointer,
19+
// typ: reflect.TypeOf(src),
20+
// }
21+
// }
22+
23+
if value == nil {
24+
return Delete(src, ptr)
25+
}
26+
sv := reflect.ValueOf(src)
27+
s := newState(ptr, Assigning)
28+
defer s.Done()
29+
if sv.Kind() != reflect.Ptr || sv.IsNil() {
30+
return &ptrError{
31+
state: *s,
32+
err: ErrNonPointer,
33+
typ: sv.Type(),
34+
}
35+
}
36+
return s.assign(sv, value)
37+
}

assign_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package jsonpointer
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
)
9+
10+
type Embedded struct {
11+
F3 string `json:"f3"`
12+
}
13+
14+
type structentry struct {
15+
Name string `json:"name"`
16+
F2 string `json:"f2"`
17+
*Embedded `json:",inline"`
18+
}
19+
20+
type mapcontainer struct {
21+
Map map[string]structentry `json:"map"`
22+
}
23+
24+
func TestAssignStructField(t *testing.T) {
25+
// assert := require.New(t)
26+
// se := structentry{}
27+
// assign := newAssignState("/f3")
28+
// err := assign.structField(
29+
// JSONPointer("/f3"),
30+
// reflect.TypeOf(&se),
31+
// reflect.ValueOf(&se),
32+
// reflect.ValueOf("value"),
33+
// )
34+
35+
// assert.NoError(err)
36+
// assert.Equal("value", se.F3)
37+
}
38+
39+
func TestAssignMapValue(t *testing.T) {
40+
// assert := require.New(t)
41+
// m := make(map[string]structentry)
42+
// ptr := JSONPointer("/foo")
43+
// assign := newAssignState(ptr)
44+
// val := structentry{Name: "fooval"}
45+
// err := assign.setMapIndex(
46+
// ptr,
47+
// reflect.TypeOf(m),
48+
// reflect.ValueOf(m),
49+
// reflect.ValueOf(val),
50+
// )
51+
// assert.NoError(err)
52+
// assert.Contains(m, "foo")
53+
// assert.Equal(val, m["foo"])
54+
}
55+
56+
func TestAssignMap(t *testing.T) {
57+
assert := require.New(t)
58+
var m map[string]structentry
59+
ptr := JSONPointer("/foo")
60+
s := newState(ptr, Assigning|Resolving)
61+
val := structentry{Name: "fooval"}
62+
err := s.assign(reflect.ValueOf(&m), val)
63+
assert.NoError(err)
64+
assert.Contains(m, "foo")
65+
assert.Equal(val, m["foo"])
66+
}
67+
68+
// if r, ok := v.Interface().(Resolver); ok {
69+
// result.resolver = r
70+
// if s.isOnlyResolving() {
71+
// result.value = v
72+
// result.typ = v.Type()
73+
// return result
74+
// }
75+
// }

delete.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package jsonpointer
2+
3+
type Deleter interface {
4+
DeleteByJSONPointer(ptr *JSONPointer) error
5+
}
6+
7+
func Delete(src interface{}, ptr JSONPointer) error {
8+
panic("not impl")
9+
}

errors.go

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package jsonpointer
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
"reflect"
7+
)
8+
9+
// TODO: need to clean these up and provide better error message\
10+
11+
var (
12+
// ErrMalformedToken is returned when a JSONPointer token is malformed.
13+
//
14+
// This error is returned by JSONPointer.Validate() which is called by
15+
// Resolve, Assign, and Delete.
16+
ErrMalformedToken = fmt.Errorf(`jsonpointer: reference must be empty or start with a "/"`)
17+
// ErrNonPointer indicates a non-pointer value was passed to Assign.
18+
ErrNonPointer = errors.New("jsonpointer: dst must be a pointer")
19+
// ErrUnexportedField indicates the given path is not reachable due to being
20+
// an unexported field.
21+
ErrUnexportedField = errors.New("jsonpointer: unexported field")
22+
// ErrInvalidKeyType indicates the key type is not supported.
23+
//
24+
// Custom key types must implement encoding.TextUnmarshaler
25+
ErrInvalidKeyType = errors.New("jsonpointer: invalid key type")
26+
// ErrNotAssignable indicates the type of the value is not assignable to the
27+
// provided path.
28+
ErrNotAssignable = errors.New("jsonpointer: invalid value type")
29+
// ErrNotFound indicates a JSONPointer is not reachable from the root object
30+
// (e.g. a nil pointer, missing map key).
31+
ErrNotFound = errors.New(`jsonpointer: token path not found`)
32+
// ErrOutOfBounds indicates an index is out of bounds for an array or slice
33+
ErrOutOfBounds = errors.New("jsonpointer: index out of bounds")
34+
// ErrInvalidReference indicates a reference is not reachable. This occurs
35+
// when a primitive leaf node is reached and the reference is not empty.
36+
ErrInvalidReference = errors.New("jsonpointer: bad reference")
37+
)
38+
39+
// Error is a base error type returned from Resolve, Assign, and Delete.
40+
type Error interface {
41+
error
42+
JSONPointer() JSONPointer
43+
CurrentJSONPointer() JSONPointer
44+
Token() (Token, bool)
45+
Operation() Operation
46+
Unwrap() error
47+
Type() reflect.Type
48+
}
49+
50+
func isError(err error) bool {
51+
_, ok := err.(Error)
52+
return ok
53+
}
54+
55+
func AsError(err error) (Error, bool) {
56+
var e Error
57+
return e, errors.As(err, &e)
58+
}
59+
60+
func newError(err error, s *state, typ reflect.Type) *ptrError {
61+
return &ptrError{
62+
err: err,
63+
typ: typ,
64+
state: *s,
65+
}
66+
}
67+
68+
type ptrError struct {
69+
state
70+
err error
71+
typ reflect.Type
72+
}
73+
74+
func (e *ptrError) Error() string {
75+
return e.err.Error()
76+
}
77+
78+
// Unwrap returns the underlying error.
79+
func (e *ptrError) Unwrap() error {
80+
return e.err
81+
}
82+
83+
// JSONPointer returns the initial JSONPointer.
84+
func (e *ptrError) JSONPointer() JSONPointer {
85+
return e.ptr
86+
}
87+
88+
// Type returns the reflect.Type of the current container object.
89+
func (e *ptrError) Type() reflect.Type {
90+
return e.typ
91+
}
92+
93+
// Token returns the token of the JSONPointer which encountered the error
94+
func (e *ptrError) Token() (Token, bool) {
95+
return e.current.NextToken()
96+
}
97+
98+
// KeyError indicates an error occurred with regards to the key of a map or
99+
// slice.
100+
type KeyError interface {
101+
Error
102+
KeyType() reflect.Type
103+
KeyValue() interface{}
104+
}
105+
106+
func IsKeyError(err error) bool {
107+
if err == nil {
108+
return false
109+
}
110+
_, ok := AsKeyError(err)
111+
return ok
112+
}
113+
114+
func AsKeyError(err error) (KeyError, bool) {
115+
var e KeyError
116+
return e, errors.As(err, &e)
117+
}
118+
119+
func newKeyError(err error, s *state, typ reflect.Type, keyValue interface{}, keyType reflect.Type) *keyError {
120+
if e, ok := err.(*keyError); ok {
121+
return e
122+
}
123+
return &keyError{
124+
ptrError: ptrError{
125+
state: *s,
126+
err: err,
127+
typ: typ,
128+
},
129+
keyValue: keyValue,
130+
keyType: keyType,
131+
}
132+
}
133+
134+
type keyError struct {
135+
ptrError
136+
keyType reflect.Type
137+
keyValue interface{}
138+
}
139+
140+
func (e *keyError) Error() string {
141+
if e.typ == nil {
142+
return e.err.Error() + " (nil)"
143+
}
144+
return e.err.Error() + " for " + e.typ.String() + "(" + e.keyType.String() + ")"
145+
}
146+
147+
func (e *keyError) KeyType() reflect.Type {
148+
return e.keyType
149+
}
150+
151+
func (e *keyError) KeyValue() interface{} {
152+
return e.keyValue
153+
}
154+
155+
// FieldError indicates an error occurred with regards to a field of a struct.
156+
type FieldError interface {
157+
Error
158+
Field() reflect.StructField
159+
}
160+
161+
type fieldError struct {
162+
ptrError
163+
field reflect.StructField
164+
}
165+
166+
func (e *fieldError) Error() string {
167+
switch {
168+
case errors.Is(e.err, ErrUnexportedField):
169+
if t, ok := e.Token(); ok {
170+
return "jsonpointer: unexported field: " + t.String() + " " + e.typ.String() + "." + e.field.Name
171+
} else {
172+
return "jsonpointer: unexported field: " + e.typ.String() + "." + e.field.Name
173+
}
174+
default:
175+
return e.ptrError.Error()
176+
}
177+
}
178+
179+
type ValueError interface {
180+
Error
181+
ValueType() reflect.Type
182+
}
183+
184+
func IsValueError(err error) bool {
185+
if err == nil {
186+
return false
187+
}
188+
_, ok := AsValueError(err)
189+
return ok
190+
}
191+
192+
func AsValueError(err error) (ValueError, bool) {
193+
var e ValueError
194+
return e, errors.As(err, &e)
195+
}
196+
197+
func newValueError(err error, s *state, typ reflect.Type, valType reflect.Type) *valueError {
198+
return &valueError{
199+
valuetype: valType,
200+
ptrError: ptrError{
201+
state: *s,
202+
err: err,
203+
typ: typ,
204+
},
205+
}
206+
}
207+
208+
type valueError struct {
209+
ptrError
210+
valuetype reflect.Type
211+
}
212+
213+
func (e *valueError) Error() string {
214+
return e.ptrError.Error() + " " + e.valuetype.String() + " for " + e.typ.String()
215+
}
216+
217+
func (e *valueError) ValueType() reflect.Type {
218+
return e.valuetype
219+
}

0 commit comments

Comments
 (0)