Skip to content

Commit

Permalink
Merge pull request #221 from danielgtaylor/fix-gron
Browse files Browse the repository at this point in the history
fix: gron output with special chars
  • Loading branch information
danielgtaylor committed Oct 3, 2023
2 parents 2c85909 + 98245d9 commit 760fbd0
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 23 deletions.
2 changes: 1 addition & 1 deletion cli/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func (t Gron) Detect(contentType string) bool {

// Marshal the value to a gron string.
func (t Gron) Marshal(value interface{}) ([]byte, error) {
pb := NewPathBuffer([]byte("body"), 4)
pb := NewPathBuffer([][]byte{[]byte("body")})
out := make([]byte, 0, 1024)
return marshalGron(pb, value, false, out)
}
Expand Down
35 changes: 13 additions & 22 deletions cli/gron.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,41 +12,30 @@ import (
"unicode"
)

// PathBuffer is a low-allocation helper for building a path string like
// `foo.bar[2].baz`. It is not goroutine-safe, but the underlying buffer can
// be re-used within the same goroutine or via a `sync.Pool`.
// PathBuffer builds up a path string from multiple parts.
type PathBuffer struct {
buf []byte
off int
parts [][]byte
}

func (b *PathBuffer) Push(s string) {
if b.off > 0 && s[0] != '[' {
b.buf = append(b.buf, '.')
b.off++
if s[0] != '[' {
s = "." + s
}
b.buf = append(b.buf, s...)
b.off += len(s)
b.parts = append(b.parts, []byte(s))
}

func (b *PathBuffer) Pop() {
for b.off > 0 {
b.off--
if b.buf[b.off] == '.' || b.buf[b.off] == '[' {
break
}
}
b.buf = b.buf[:b.off]
b.parts = b.parts[:len(b.parts)-1]
}

func (b *PathBuffer) Bytes() []byte {
return b.buf[:b.off]
return bytes.Join(b.parts, []byte{})
}

// NewPathBuffer creates a new path buffer with the given underlying byte slice
// and offset within that slice (for pre-loading with some path data).
func NewPathBuffer(buf []byte, offset int) *PathBuffer {
return &PathBuffer{buf: buf, off: offset}
// NewPathBuffer creates a new path buffer with the given underlying initial
// data loaded into it.
func NewPathBuffer(parts [][]byte) *PathBuffer {
return &PathBuffer{parts: parts}
}

// validFirstRune returns true for runes that are valid
Expand All @@ -72,6 +61,8 @@ func identifier(s string) string {
return s
}

s = strings.ReplaceAll(s, `"`, `\"`)

return fmt.Sprintf(`["%s"]`, s)
}

Expand Down
9 changes: 9 additions & 0 deletions cli/gron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ func TestGronMarshal(t *testing.T) {
{"e": "world & i <3 restish"},
{"f": []any{1, 2}, "g": time.Time{}, "h": []byte("foo")},
{"for": map[int]int{1: 2}},
{"dotted.name": "foo"},
{"name[with]brackets": "bar"},
{"name\"with": "quote"},
}},
private: true,
}
Expand All @@ -52,6 +55,12 @@ body.d[1].h = "Zm9v";
body.d[2] = {};
body.d[2].for = {};
body.d[2].for["1"] = 2;
body.d[3] = {};
body.d[3]["dotted.name"] = "foo";
body.d[4] = {};
body.d[4]["name[with]brackets"] = "bar";
body.d[5] = {};
body.d[5]["name\"with"] = "quote";
`, string(b))

// Invalid types should result in an error!
Expand Down

0 comments on commit 760fbd0

Please sign in to comment.