summaryrefslogtreecommitdiff
path: root/vendor/github.com/goccy/go-json/internal/decoder/path.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/goccy/go-json/internal/decoder/path.go')
-rw-r--r--vendor/github.com/goccy/go-json/internal/decoder/path.go670
1 files changed, 670 insertions, 0 deletions
diff --git a/vendor/github.com/goccy/go-json/internal/decoder/path.go b/vendor/github.com/goccy/go-json/internal/decoder/path.go
new file mode 100644
index 000000000..a15ff69e3
--- /dev/null
+++ b/vendor/github.com/goccy/go-json/internal/decoder/path.go
@@ -0,0 +1,670 @@
+package decoder
+
+import (
+ "fmt"
+ "reflect"
+ "strconv"
+
+ "github.com/goccy/go-json/internal/errors"
+ "github.com/goccy/go-json/internal/runtime"
+)
+
+type PathString string
+
+func (s PathString) Build() (*Path, error) {
+ builder := new(PathBuilder)
+ return builder.Build([]rune(s))
+}
+
+type PathBuilder struct {
+ root PathNode
+ node PathNode
+ singleQuotePathSelector bool
+ doubleQuotePathSelector bool
+}
+
+func (b *PathBuilder) Build(buf []rune) (*Path, error) {
+ node, err := b.build(buf)
+ if err != nil {
+ return nil, err
+ }
+ return &Path{
+ node: node,
+ RootSelectorOnly: node == nil,
+ SingleQuotePathSelector: b.singleQuotePathSelector,
+ DoubleQuotePathSelector: b.doubleQuotePathSelector,
+ }, nil
+}
+
+func (b *PathBuilder) build(buf []rune) (PathNode, error) {
+ if len(buf) == 0 {
+ return nil, errors.ErrEmptyPath()
+ }
+ if buf[0] != '$' {
+ return nil, errors.ErrInvalidPath("JSON Path must start with a $ character")
+ }
+ if len(buf) == 1 {
+ return nil, nil
+ }
+ buf = buf[1:]
+ offset, err := b.buildNext(buf)
+ if err != nil {
+ return nil, err
+ }
+ if len(buf) > offset {
+ return nil, errors.ErrInvalidPath("remain invalid path %q", buf[offset:])
+ }
+ return b.root, nil
+}
+
+func (b *PathBuilder) buildNextCharIfExists(buf []rune, cursor int) (int, error) {
+ if len(buf) > cursor {
+ offset, err := b.buildNext(buf[cursor:])
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ }
+ return cursor, nil
+}
+
+func (b *PathBuilder) buildNext(buf []rune) (int, error) {
+ switch buf[0] {
+ case '.':
+ if len(buf) == 1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
+ }
+ offset, err := b.buildSelector(buf[1:])
+ if err != nil {
+ return 0, err
+ }
+ return offset + 1, nil
+ case '[':
+ if len(buf) == 1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
+ }
+ offset, err := b.buildIndex(buf[1:])
+ if err != nil {
+ return 0, err
+ }
+ return offset + 1, nil
+ default:
+ return 0, errors.ErrInvalidPath("expect dot or left bracket character. but found %c character", buf[0])
+ }
+}
+
+func (b *PathBuilder) buildSelector(buf []rune) (int, error) {
+ switch buf[0] {
+ case '.':
+ if len(buf) == 1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with double dot character")
+ }
+ offset, err := b.buildPathRecursive(buf[1:])
+ if err != nil {
+ return 0, err
+ }
+ return 1 + offset, nil
+ case '[', ']', '$', '*':
+ return 0, errors.ErrInvalidPath("found invalid path character %c after dot", buf[0])
+ }
+ for cursor := 0; cursor < len(buf); cursor++ {
+ switch buf[cursor] {
+ case '$', '*', ']':
+ return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor])
+ case '.':
+ if cursor+1 >= len(buf) {
+ return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
+ }
+ selector := buf[:cursor]
+ b.addSelectorNode(string(selector))
+ offset, err := b.buildSelector(buf[cursor+1:])
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ case '[':
+ if cursor+1 >= len(buf) {
+ return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
+ }
+ selector := buf[:cursor]
+ b.addSelectorNode(string(selector))
+ offset, err := b.buildIndex(buf[cursor+1:])
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ case '"':
+ if cursor+1 >= len(buf) {
+ return 0, errors.ErrInvalidPath("JSON Path ends with double quote character")
+ }
+ offset, err := b.buildQuoteSelector(buf[cursor+1:], DoubleQuotePathSelector)
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ }
+ }
+ b.addSelectorNode(string(buf))
+ return len(buf), nil
+}
+
+func (b *PathBuilder) buildQuoteSelector(buf []rune, sel QuotePathSelector) (int, error) {
+ switch buf[0] {
+ case '[', ']', '$', '.', '*', '\'', '"':
+ return 0, errors.ErrInvalidPath("found invalid path character %c after quote", buf[0])
+ }
+ for cursor := 0; cursor < len(buf); cursor++ {
+ switch buf[cursor] {
+ case '\'':
+ if sel != SingleQuotePathSelector {
+ return 0, errors.ErrInvalidPath("found double quote character in field selector with single quote context")
+ }
+ if len(buf) <= cursor+1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with single quote character in field selector context")
+ }
+ if buf[cursor+1] != ']' {
+ return 0, errors.ErrInvalidPath("expect right bracket for field selector with single quote but found %c", buf[cursor+1])
+ }
+ selector := buf[:cursor]
+ b.addSelectorNode(string(selector))
+ b.singleQuotePathSelector = true
+ return b.buildNextCharIfExists(buf, cursor+2)
+ case '"':
+ if sel != DoubleQuotePathSelector {
+ return 0, errors.ErrInvalidPath("found single quote character in field selector with double quote context")
+ }
+ selector := buf[:cursor]
+ b.addSelectorNode(string(selector))
+ b.doubleQuotePathSelector = true
+ return b.buildNextCharIfExists(buf, cursor+1)
+ }
+ }
+ return 0, errors.ErrInvalidPath("couldn't find quote character in selector quote path context")
+}
+
+func (b *PathBuilder) buildPathRecursive(buf []rune) (int, error) {
+ switch buf[0] {
+ case '.', '[', ']', '$', '*':
+ return 0, errors.ErrInvalidPath("found invalid path character %c after double dot", buf[0])
+ }
+ for cursor := 0; cursor < len(buf); cursor++ {
+ switch buf[cursor] {
+ case '$', '*', ']':
+ return 0, errors.ErrInvalidPath("found %c character in field selector context", buf[cursor])
+ case '.':
+ if cursor+1 >= len(buf) {
+ return 0, errors.ErrInvalidPath("JSON Path ends with dot character")
+ }
+ selector := buf[:cursor]
+ b.addRecursiveNode(string(selector))
+ offset, err := b.buildSelector(buf[cursor+1:])
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ case '[':
+ if cursor+1 >= len(buf) {
+ return 0, errors.ErrInvalidPath("JSON Path ends with left bracket character")
+ }
+ selector := buf[:cursor]
+ b.addRecursiveNode(string(selector))
+ offset, err := b.buildIndex(buf[cursor+1:])
+ if err != nil {
+ return 0, err
+ }
+ return cursor + 1 + offset, nil
+ }
+ }
+ b.addRecursiveNode(string(buf))
+ return len(buf), nil
+}
+
+func (b *PathBuilder) buildIndex(buf []rune) (int, error) {
+ switch buf[0] {
+ case '.', '[', ']', '$':
+ return 0, errors.ErrInvalidPath("found invalid path character %c after left bracket", buf[0])
+ case '\'':
+ if len(buf) == 1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with single quote character")
+ }
+ offset, err := b.buildQuoteSelector(buf[1:], SingleQuotePathSelector)
+ if err != nil {
+ return 0, err
+ }
+ return 1 + offset, nil
+ case '*':
+ if len(buf) == 1 {
+ return 0, errors.ErrInvalidPath("JSON Path ends with star character")
+ }
+ if buf[1] != ']' {
+ return 0, errors.ErrInvalidPath("expect right bracket character for index all path but found %c character", buf[1])
+ }
+ b.addIndexAllNode()
+ offset := len("*]")
+ if len(buf) > 2 {
+ buildOffset, err := b.buildNext(buf[2:])
+ if err != nil {
+ return 0, err
+ }
+ return offset + buildOffset, nil
+ }
+ return offset, nil
+ }
+
+ for cursor := 0; cursor < len(buf); cursor++ {
+ switch buf[cursor] {
+ case ']':
+ index, err := strconv.ParseInt(string(buf[:cursor]), 10, 64)
+ if err != nil {
+ return 0, errors.ErrInvalidPath("%q is unexpected index path", buf[:cursor])
+ }
+ b.addIndexNode(int(index))
+ return b.buildNextCharIfExists(buf, cursor+1)
+ }
+ }
+ return 0, errors.ErrInvalidPath("couldn't find right bracket character in index path context")
+}
+
+func (b *PathBuilder) addIndexAllNode() {
+ node := newPathIndexAllNode()
+ if b.root == nil {
+ b.root = node
+ b.node = node
+ } else {
+ b.node = b.node.chain(node)
+ }
+}
+
+func (b *PathBuilder) addRecursiveNode(selector string) {
+ node := newPathRecursiveNode(selector)
+ if b.root == nil {
+ b.root = node
+ b.node = node
+ } else {
+ b.node = b.node.chain(node)
+ }
+}
+
+func (b *PathBuilder) addSelectorNode(name string) {
+ node := newPathSelectorNode(name)
+ if b.root == nil {
+ b.root = node
+ b.node = node
+ } else {
+ b.node = b.node.chain(node)
+ }
+}
+
+func (b *PathBuilder) addIndexNode(idx int) {
+ node := newPathIndexNode(idx)
+ if b.root == nil {
+ b.root = node
+ b.node = node
+ } else {
+ b.node = b.node.chain(node)
+ }
+}
+
+type QuotePathSelector int
+
+const (
+ SingleQuotePathSelector QuotePathSelector = 1
+ DoubleQuotePathSelector QuotePathSelector = 2
+)
+
+type Path struct {
+ node PathNode
+ RootSelectorOnly bool
+ SingleQuotePathSelector bool
+ DoubleQuotePathSelector bool
+}
+
+func (p *Path) Field(sel string) (PathNode, bool, error) {
+ if p.node == nil {
+ return nil, false, nil
+ }
+ return p.node.Field(sel)
+}
+
+func (p *Path) Get(src, dst reflect.Value) error {
+ if p.node == nil {
+ return nil
+ }
+ return p.node.Get(src, dst)
+}
+
+func (p *Path) String() string {
+ if p.node == nil {
+ return "$"
+ }
+ return p.node.String()
+}
+
+type PathNode interface {
+ fmt.Stringer
+ Index(idx int) (PathNode, bool, error)
+ Field(fieldName string) (PathNode, bool, error)
+ Get(src, dst reflect.Value) error
+ chain(PathNode) PathNode
+ target() bool
+ single() bool
+}
+
+type BasePathNode struct {
+ child PathNode
+}
+
+func (n *BasePathNode) chain(node PathNode) PathNode {
+ n.child = node
+ return node
+}
+
+func (n *BasePathNode) target() bool {
+ return n.child == nil
+}
+
+func (n *BasePathNode) single() bool {
+ return true
+}
+
+type PathSelectorNode struct {
+ *BasePathNode
+ selector string
+}
+
+func newPathSelectorNode(selector string) *PathSelectorNode {
+ return &PathSelectorNode{
+ BasePathNode: &BasePathNode{},
+ selector: selector,
+ }
+}
+
+func (n *PathSelectorNode) Index(idx int) (PathNode, bool, error) {
+ return nil, false, &errors.PathError{}
+}
+
+func (n *PathSelectorNode) Field(fieldName string) (PathNode, bool, error) {
+ if n.selector == fieldName {
+ return n.child, true, nil
+ }
+ return nil, false, nil
+}
+
+func (n *PathSelectorNode) Get(src, dst reflect.Value) error {
+ switch src.Type().Kind() {
+ case reflect.Map:
+ iter := src.MapRange()
+ for iter.Next() {
+ key, ok := iter.Key().Interface().(string)
+ if !ok {
+ return fmt.Errorf("invalid map key type %T", src.Type().Key())
+ }
+ child, found, err := n.Field(key)
+ if err != nil {
+ return err
+ }
+ if found {
+ if child != nil {
+ return child.Get(iter.Value(), dst)
+ }
+ return AssignValue(iter.Value(), dst)
+ }
+ }
+ case reflect.Struct:
+ typ := src.Type()
+ for i := 0; i < typ.Len(); i++ {
+ tag := runtime.StructTagFromField(typ.Field(i))
+ child, found, err := n.Field(tag.Key)
+ if err != nil {
+ return err
+ }
+ if found {
+ if child != nil {
+ return child.Get(src.Field(i), dst)
+ }
+ return AssignValue(src.Field(i), dst)
+ }
+ }
+ case reflect.Ptr:
+ return n.Get(src.Elem(), dst)
+ case reflect.Interface:
+ return n.Get(reflect.ValueOf(src.Interface()), dst)
+ case reflect.Float64, reflect.String, reflect.Bool:
+ return AssignValue(src, dst)
+ }
+ return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type())
+}
+
+func (n *PathSelectorNode) String() string {
+ s := fmt.Sprintf(".%s", n.selector)
+ if n.child != nil {
+ s += n.child.String()
+ }
+ return s
+}
+
+type PathIndexNode struct {
+ *BasePathNode
+ selector int
+}
+
+func newPathIndexNode(selector int) *PathIndexNode {
+ return &PathIndexNode{
+ BasePathNode: &BasePathNode{},
+ selector: selector,
+ }
+}
+
+func (n *PathIndexNode) Index(idx int) (PathNode, bool, error) {
+ if n.selector == idx {
+ return n.child, true, nil
+ }
+ return nil, false, nil
+}
+
+func (n *PathIndexNode) Field(fieldName string) (PathNode, bool, error) {
+ return nil, false, &errors.PathError{}
+}
+
+func (n *PathIndexNode) Get(src, dst reflect.Value) error {
+ switch src.Type().Kind() {
+ case reflect.Array, reflect.Slice:
+ if src.Len() > n.selector {
+ if n.child != nil {
+ return n.child.Get(src.Index(n.selector), dst)
+ }
+ return AssignValue(src.Index(n.selector), dst)
+ }
+ case reflect.Ptr:
+ return n.Get(src.Elem(), dst)
+ case reflect.Interface:
+ return n.Get(reflect.ValueOf(src.Interface()), dst)
+ }
+ return fmt.Errorf("failed to get [%d] value from %s", n.selector, src.Type())
+}
+
+func (n *PathIndexNode) String() string {
+ s := fmt.Sprintf("[%d]", n.selector)
+ if n.child != nil {
+ s += n.child.String()
+ }
+ return s
+}
+
+type PathIndexAllNode struct {
+ *BasePathNode
+}
+
+func newPathIndexAllNode() *PathIndexAllNode {
+ return &PathIndexAllNode{
+ BasePathNode: &BasePathNode{},
+ }
+}
+
+func (n *PathIndexAllNode) Index(idx int) (PathNode, bool, error) {
+ return n.child, true, nil
+}
+
+func (n *PathIndexAllNode) Field(fieldName string) (PathNode, bool, error) {
+ return nil, false, &errors.PathError{}
+}
+
+func (n *PathIndexAllNode) Get(src, dst reflect.Value) error {
+ switch src.Type().Kind() {
+ case reflect.Array, reflect.Slice:
+ var arr []interface{}
+ for i := 0; i < src.Len(); i++ {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ if n.child != nil {
+ if err := n.child.Get(src.Index(i), rv); err != nil {
+ return err
+ }
+ } else {
+ if err := AssignValue(src.Index(i), rv); err != nil {
+ return err
+ }
+ }
+ arr = append(arr, v)
+ }
+ if err := AssignValue(reflect.ValueOf(arr), dst); err != nil {
+ return err
+ }
+ return nil
+ case reflect.Ptr:
+ return n.Get(src.Elem(), dst)
+ case reflect.Interface:
+ return n.Get(reflect.ValueOf(src.Interface()), dst)
+ }
+ return fmt.Errorf("failed to get all value from %s", src.Type())
+}
+
+func (n *PathIndexAllNode) String() string {
+ s := "[*]"
+ if n.child != nil {
+ s += n.child.String()
+ }
+ return s
+}
+
+type PathRecursiveNode struct {
+ *BasePathNode
+ selector string
+}
+
+func newPathRecursiveNode(selector string) *PathRecursiveNode {
+ node := newPathSelectorNode(selector)
+ return &PathRecursiveNode{
+ BasePathNode: &BasePathNode{
+ child: node,
+ },
+ selector: selector,
+ }
+}
+
+func (n *PathRecursiveNode) Field(fieldName string) (PathNode, bool, error) {
+ if n.selector == fieldName {
+ return n.child, true, nil
+ }
+ return nil, false, nil
+}
+
+func (n *PathRecursiveNode) Index(_ int) (PathNode, bool, error) {
+ return n, true, nil
+}
+
+func valueToSliceValue(v interface{}) []interface{} {
+ rv := reflect.ValueOf(v)
+ ret := []interface{}{}
+ if rv.Type().Kind() == reflect.Slice || rv.Type().Kind() == reflect.Array {
+ for i := 0; i < rv.Len(); i++ {
+ ret = append(ret, rv.Index(i).Interface())
+ }
+ return ret
+ }
+ return []interface{}{v}
+}
+
+func (n *PathRecursiveNode) Get(src, dst reflect.Value) error {
+ if n.child == nil {
+ return fmt.Errorf("failed to get by recursive path ..%s", n.selector)
+ }
+ var arr []interface{}
+ switch src.Type().Kind() {
+ case reflect.Map:
+ iter := src.MapRange()
+ for iter.Next() {
+ key, ok := iter.Key().Interface().(string)
+ if !ok {
+ return fmt.Errorf("invalid map key type %T", src.Type().Key())
+ }
+ child, found, err := n.Field(key)
+ if err != nil {
+ return err
+ }
+ if found {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ _ = child.Get(iter.Value(), rv)
+ arr = append(arr, valueToSliceValue(v)...)
+ } else {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ _ = n.Get(iter.Value(), rv)
+ if v != nil {
+ arr = append(arr, valueToSliceValue(v)...)
+ }
+ }
+ }
+ _ = AssignValue(reflect.ValueOf(arr), dst)
+ return nil
+ case reflect.Struct:
+ typ := src.Type()
+ for i := 0; i < typ.Len(); i++ {
+ tag := runtime.StructTagFromField(typ.Field(i))
+ child, found, err := n.Field(tag.Key)
+ if err != nil {
+ return err
+ }
+ if found {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ _ = child.Get(src.Field(i), rv)
+ arr = append(arr, valueToSliceValue(v)...)
+ } else {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ _ = n.Get(src.Field(i), rv)
+ if v != nil {
+ arr = append(arr, valueToSliceValue(v)...)
+ }
+ }
+ }
+ _ = AssignValue(reflect.ValueOf(arr), dst)
+ return nil
+ case reflect.Array, reflect.Slice:
+ for i := 0; i < src.Len(); i++ {
+ var v interface{}
+ rv := reflect.ValueOf(&v)
+ _ = n.Get(src.Index(i), rv)
+ if v != nil {
+ arr = append(arr, valueToSliceValue(v)...)
+ }
+ }
+ _ = AssignValue(reflect.ValueOf(arr), dst)
+ return nil
+ case reflect.Ptr:
+ return n.Get(src.Elem(), dst)
+ case reflect.Interface:
+ return n.Get(reflect.ValueOf(src.Interface()), dst)
+ }
+ return fmt.Errorf("failed to get %s value from %s", n.selector, src.Type())
+}
+
+func (n *PathRecursiveNode) String() string {
+ s := fmt.Sprintf("..%s", n.selector)
+ if n.child != nil {
+ s += n.child.String()
+ }
+ return s
+}