Decode native diff paths without revalidation

This commit is contained in:
2026-11-07 16:00:28 +00:00
parent c4b5bcdbc2
commit e950f61c7f
4 changed files with 23 additions and 41 deletions

View File

@@ -8,39 +8,17 @@ import (
configkit "go.maximumdirect.net/configkit"
)
func decodeJSONPointer(pointer string) ([]string, error) {
func decodeJSONPointer(path configkit.Path) []string {
pointer := path.String()
if pointer == "" {
return nil, nil
return nil
}
if pointer[0] != '/' {
return nil, fmt.Errorf("decode JSON pointer %q: path must start with /", pointer)
}
parts := strings.Split(pointer[1:], "/")
decoder := strings.NewReplacer("~1", "/", "~0", "~")
for index, part := range parts {
var decoded strings.Builder
decoded.Grow(len(part))
for offset := 0; offset < len(part); offset++ {
if part[offset] != '~' {
decoded.WriteByte(part[offset])
continue
}
if offset+1 >= len(part) {
return nil, fmt.Errorf("decode JSON pointer %q: incomplete escape in token %d", pointer, index)
}
offset++
switch part[offset] {
case '0':
decoded.WriteByte('~')
case '1':
decoded.WriteByte('/')
default:
return nil, fmt.Errorf("decode JSON pointer %q: invalid escape in token %d", pointer, index)
}
}
parts[index] = decoded.String()
parts[index] = decoder.Replace(part)
}
return parts, nil
return parts
}
func placeReportValue(root any, path []string, value any) (any, error) {
@@ -135,10 +113,7 @@ func renderDiffReport(differences []configkit.Difference) (any, error) {
if !difference.Right.Present {
continue
}
tokens, err := decodeJSONPointer(path)
if err != nil {
return nil, fmt.Errorf("difference at %q: %w", path, err)
}
tokens := decodeJSONPointer(difference.Path)
value, err := commandkit.DecodeYAMLReport(strings.NewReader(difference.Right.YAML))
if err != nil {
return nil, fmt.Errorf("difference at %q: %w", path, err)

View File

@@ -3,6 +3,8 @@ package ckconfig
import (
"reflect"
"testing"
configkit "go.maximumdirect.net/configkit"
)
func TestDecodeJSONPointerPreservesSemanticTokens(t *testing.T) {
@@ -16,21 +18,18 @@ func TestDecodeJSONPointerPreservesSemanticTokens(t *testing.T) {
{pointer: "/0/../a.b/50%", want: []string{"0", "..", "a.b", "50%"}},
{pointer: "/a~1b/c~0d", want: []string{"a/b", "c~d"}},
{pointer: "/~01", want: []string{"~1"}},
{pointer: "/café", want: []string{"café"}},
}
for _, test := range tests {
got, err := decodeJSONPointer(test.pointer)
path, err := configkit.ParsePath(test.pointer)
if err != nil {
t.Fatalf("decode %q: %v", test.pointer, err)
t.Fatal(err)
}
got := decodeJSONPointer(path)
if !reflect.DeepEqual(got, test.want) {
t.Errorf("decode %q = %#v, want %#v", test.pointer, got, test.want)
}
}
for _, pointer := range []string{"missing-leading-slash", "/bad~", "/bad~2escape"} {
if _, err := decodeJSONPointer(pointer); err == nil {
t.Errorf("decode %q unexpectedly succeeded", pointer)
}
}
}
func TestPlaceReportValue(t *testing.T) {