Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ linters:
disable:
- depguard
- funlen
- goconst
- godox
- gomodguard
- gomodguard_v2
- exhaustruct
- nlreturn
- nonamedreturns
Expand Down
13 changes: 7 additions & 6 deletions dash_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import (
"github.com/go-openapi/testify/v2/require"
)

// RFC 6901 §4: the "-" token refers to the (nonexistent) element after the
// last array element. It is always an error on Get/Offset, valid only as
// the terminal token of a Set against a slice (append, per RFC 6902).
// RFC 6901 §4: the "-" token refers to the (nonexistent) element after the last array element.
// It is always an error on Get/Offset, valid only as the terminal token of a Set against a slice
// (append, per RFC 6902).

func TestDashToken_GetAlwaysErrors(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -56,7 +56,8 @@ func TestDashToken_GetAlwaysErrors(t *testing.T) {
})

t.Run("dash on map key is a regular lookup, not an error", func(t *testing.T) {
// "-" is only special for arrays. A literal "-" key in a map is fine.
// "-" is only special for arrays.
// A literal "-" key in a map is fine.
doc := map[string]any{"-": 42}
p, err := New("/-")
require.NoError(t, err)
Expand Down Expand Up @@ -208,8 +209,8 @@ func (d *dashSetter) JSONSet(key string, value any) error {
func TestDashToken_JSONSetableReceivesRawDash(t *testing.T) {
t.Parallel()

// When the terminal parent implements JSONSetable, the dash token is
// passed through verbatim. Semantics are the user type's responsibility.
// When the terminal parent implements JSONSetable, the dash token is passed through verbatim.
// Semantics are the user type's responsibility.
ds := &dashSetter{}
p, err := New("/-")
require.NoError(t, err)
Expand Down
15 changes: 8 additions & 7 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ const (
// ErrUnsupportedValueType indicates that a value of the wrong type is being set.
ErrUnsupportedValueType pointerError = "only structs, pointers, maps and slices are supported for setting values"

// ErrDashToken indicates use of the RFC 6901 "-" reference token
// in a context where it cannot be resolved.
// ErrDashToken indicates use of the RFC 6901 "-" reference token in a context where it cannot be
// resolved.
//
// Per RFC 6901 §4 the "-" token refers to the (nonexistent) element
// after the last array element. It may only be used as the terminal
// token of a [Pointer.Set] against a slice, where it means "append".
// Any other use (get, offset, intermediate traversal, non-slice target)
// is an error condition that wraps this sentinel.
// Per RFC 6901 §4 the "-" token refers to the (nonexistent) element after the last array element.
// It may only be used as the terminal token of a [Pointer.Set] against a slice, where it means
// "append".
//
// Any other use (get, offset, intermediate traversal, non-slice target) is an error condition that
// wraps this sentinel.
ErrDashToken pointerError = `the "-" array token cannot be resolved here` //nolint:gosec // G101 false positive: this is a JSON Pointer reference token, not a credential.
)

Expand Down
29 changes: 14 additions & 15 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"errors"
"fmt"

"github.com/go-openapi/swag/jsonname"
"github.com/go-openapi/jsonpointer/jsonname"
)

var ErrExampleStruct = errors.New("example error")
Expand Down Expand Up @@ -60,7 +60,7 @@ func ExampleNew() {
// key contains "/"
fmt.Printf("pointer to key %q: %q\n", Unescape("foo~1"), escaped1.String())

// output:
// Output:
// empty pointer: ""
// pointer to object key: "/foo"
// pointer to array element: "/foo/1"
Expand Down Expand Up @@ -132,10 +132,10 @@ func ExamplePointer_Set() {
// doc: jsonpointer.exampleDocument{Foo:[]string{"bar", "hey my"}}
}

// ExamplePointer_Set_append demonstrates the RFC 6901 "-" token as an
// append operation on a slice. On nested slices reached through an
// addressable parent (map entry, pointer to struct, ...), the append is
// performed in place and the returned document is the same reference.
// ExamplePointer_Set_append demonstrates the RFC 6901 "-" token as an append operation on a slice.
//
// On nested slices reached through an addressable parent (map entry, pointer to struct, ...), the
// append is performed in place and the returned document is the same reference.
func ExamplePointer_Set_append() {
doc := map[string]any{"foo": []any{"bar"}}

Expand All @@ -154,15 +154,14 @@ func ExamplePointer_Set_append() {

fmt.Printf("doc: %v\n", doc["foo"])

// Output:
// doc: [bar baz]
// Output: doc: [bar baz]
}

// ExamplePointer_Set_appendTopLevelSlice shows the one case where the
// returned document is load-bearing: appending to a top-level slice
// passed by value. The library cannot rebind the slice header in the
// caller's variable, so callers must use the returned document (or pass
// *[]T to get in-place rebind).
// ExamplePointer_Set_appendTopLevelSlice shows the one case where the returned document is
// load-bearing: appending to a top-level slice passed by value.
//
// The library cannot rebind the slice header in the caller's variable, so callers must use the
// returned document (or pass *[]T to get in-place rebind).
func ExamplePointer_Set_appendTopLevelSlice() {
doc := []int{1, 2}

Expand All @@ -188,8 +187,8 @@ func ExamplePointer_Set_appendTopLevelSlice() {
// returned: [1 2 3]
}

// ExampleUseGoNameProvider contrasts the two [NameProvider] implementations
// shipped by [github.com/go-openapi/swag/jsonname]:
// ExampleUseGoNameProvider contrasts the two [NameProvider] implementations shipped by
// [github.com/go-openapi/jsonpointer/jsonname]:
//
// - the default provider requires a `json` struct tag to expose a field;
// - the Go-name provider follows encoding/json conventions and accepts
Expand Down
5 changes: 1 addition & 4 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
module github.com/go-openapi/jsonpointer

require (
github.com/go-openapi/swag/jsonname v0.26.1
github.com/go-openapi/testify/v2 v2.6.0
)
require github.com/go-openapi/testify/v2 v2.6.0

go 1.25.0
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,4 +1,2 @@
github.com/go-openapi/swag/jsonname v0.26.1 h1:VReupaV6WxlAsCn0e4DUfgV6bPmINnPpyJDLqSfNPcE=
github.com/go-openapi/swag/jsonname v0.26.1/go.mod h1:OvdW6BoWoj33pTfi7x9vFrgmT+fk7aw0BRwvCE0YOuc=
github.com/go-openapi/testify/v2 v2.6.0 h1:5PKH2HE7YJ/LuRPQGvSxBRlFXNQhSetBLlGAgUEu3ug=
github.com/go-openapi/testify/v2 v2.6.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
2 changes: 1 addition & 1 deletion iface_example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ func Example_iface() {

fmt.Printf("updated doc: %v", doc)

// output:
// Output:
// propA (string): initial value for a
// propB (string): initial value for b
// propC: key "extra" not found: example error
Expand Down
35 changes: 19 additions & 16 deletions ifaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,42 @@ package jsonpointer

import "reflect"

// JSONPointable is an interface for structs to implement,
// when they need to customize the json pointer process or want to avoid the use of reflection.
// JSONPointable is an interface for structs to implement, when they need to customize the json
// pointer process or want to avoid the use of reflection.
type JSONPointable interface {
// JSONLookup returns a value pointed at this (unescaped) key.
JSONLookup(key string) (any, error)
}

// JSONSetable is an interface for structs to implement,
// when they need to customize the json pointer process or want to avoid the use of reflection.
// JSONSetable is an interface for structs to implement, when they need to customize the json
// pointer process or want to avoid the use of reflection.
//
// # Handling of the RFC 6901 "-" token
//
// When a type implementing JSONSetable is the terminal parent of a [Pointer.Set]
// call, the library passes the raw reference token to JSONSet without
// interpretation. In particular, the RFC 6901 "-" token (which conventionally
// means "append" for arrays, per RFC 6902) is forwarded verbatim as the key
// argument. Implementations that model an array-like container are expected
// to give "-" the append semantics; implementations that do not should return
// an error wrapping [ErrDashToken] (or [ErrPointer]) for clarity.
// When a type implementing JSONSetable is the terminal parent of a [Pointer.Set] call, the library
// passes the raw reference token to JSONSet without interpretation.
//
// Implementations are responsible for any in-place mutation: the library does
// not attempt to rebind the result of JSONSet into a parent container.
// In particular, the RFC 6901 "-" token (which conventionally means "append" for arrays, per RFC
// 6902) is forwarded verbatim as the key argument.
//
// Implementations that model an array-like container are expected to give "-" the append semantics;
// implementations that do not should return an error wrapping [ErrDashToken] (or [ErrPointer]) for
// clarity.
//
// Implementations are responsible for any in-place mutation: the library does not attempt to rebind
// the result of JSONSet into a parent container.
type JSONSetable interface {
// JSONSet sets the value pointed at the (unescaped) key.
//
// The key may be the RFC 6901 "-" token when the pointer targets a
// slice-like member; see the interface documentation for details.
// The key may be the RFC 6901 "-" token when the pointer targets a slice-like member; see the
// interface documentation for details.
JSONSet(key string, value any) error
}

// NameProvider knows how to resolve go struct fields into json names.
//
// The default provider is brought by [github.com/go-openapi/swag/jsonname.DefaultJSONNameProvider].
// The default provider is brought by
// [github.com/go-openapi/jsonpointer/jsonname.DefaultJSONNameProvider].
type NameProvider interface {
// GetGoName gets the go name for a json property name
GetGoName(subject any, name string) (string, bool)
Expand Down
5 changes: 5 additions & 0 deletions jsonname/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0

// Package jsonname is a provider of json property names from go properties.
package jsonname
Loading
Loading