hub/utils/json.go

105 строки
2.0 KiB
Go

package utils
import (
"encoding/json"
"fmt"
"io"
"strings"
)
type state struct {
isObject bool
isArray bool
arrayIndex int
objectKey string
parentState *state
}
func stateKey(s *state) string {
k := ""
if s.parentState != nil {
k = stateKey(s.parentState)
}
if s.isObject {
return fmt.Sprintf("%s.%s", k, s.objectKey)
} else if s.isArray {
return fmt.Sprintf("%s.[%d]", k, s.arrayIndex)
} else {
return k
}
}
func JSONPath(out io.Writer, src io.Reader, colorize bool) (hasNextPage bool, endCursor string) {
dec := json.NewDecoder(src)
dec.UseNumber()
s := &state{}
postEmit := func() {
if s.isObject {
s.objectKey = ""
} else if s.isArray {
s.arrayIndex++
}
}
color := func(c string, t interface{}) string {
if colorize {
return fmt.Sprintf("\033[%sm%s\033[m", c, t)
} else if tt, ok := t.(string); ok {
return tt
} else {
return fmt.Sprintf("%s", t)
}
}
for {
token, err := dec.Token()
if err == io.EOF {
break
} else if err != nil {
panic(err)
}
if delim, ok := token.(json.Delim); ok {
switch delim {
case '{':
s = &state{isObject: true, parentState: s}
case '[':
s = &state{isArray: true, parentState: s}
case '}', ']':
s = s.parentState
postEmit()
default:
panic("unknown delim")
}
} else {
if s.isObject && s.objectKey == "" {
s.objectKey = token.(string)
} else {
k := stateKey(s)
fmt.Fprintf(out, "%s\t", color("0;36", k))
switch tt := token.(type) {
case string:
fmt.Fprintf(out, "%s\n", strings.Replace(tt, "\n", "\\n", -1))
if strings.HasSuffix(k, ".pageInfo.endCursor") {
endCursor = tt
}
case json.Number:
fmt.Fprintf(out, "%s\n", color("0;35", tt))
case nil:
fmt.Fprintf(out, "\n")
case bool:
fmt.Fprintf(out, "%s\n", color("1;33", fmt.Sprintf("%v", tt)))
if strings.HasSuffix(k, ".pageInfo.hasNextPage") {
hasNextPage = tt
}
default:
panic("unknown type")
}
postEmit()
}
}
}
return
}