package jpath import ( . "github.com/pelletier/go-toml" ) type QueryPath []PathFn type PathFn func(context interface{}, next QueryPath) func (path QueryPath) Fn(context interface{}) { path[0](context, path[1:]) } func treeValue(tree *TomlTree, key string) interface{} { return tree.GetPath([]string{key}) } func matchKeyFn(name string) PathFn { return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { item := treeValue(tree, name) if item != nil { next.Fn(item) } } } } func matchIndexFn(idx int) PathFn { return func(context interface{}, next QueryPath) { if arr, ok := context.([]interface{}); ok { if idx < len(arr) && idx >= 0 { next.Fn(arr[idx]) } } } } func matchSliceFn(start, end, step int) PathFn { return func(context interface{}, next QueryPath) { if arr, ok := context.([]interface{}); ok { // adjust indexes for negative values, reverse ordering realStart, realEnd := start, end if realStart < 0 { realStart = len(arr) + realStart } if realEnd < 0 { realEnd = len(arr) + realEnd } if realEnd < realStart { realEnd, realStart = realStart, realEnd // swap } // loop and gather for idx := realStart; idx < realEnd; idx += step { next.Fn(arr[idx]) } } } } func matchAnyFn() PathFn { return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { for _, key := range tree.Keys() { item := treeValue(tree, key) next.Fn(item) } } } } func matchUnionFn(union QueryPath) PathFn { return func(context interface{}, next QueryPath) { for _, fn := range union { fn(context, next) } } } func matchRecurseFn() PathFn { return func(context interface{}, next QueryPath) { if tree, ok := context.(*TomlTree); ok { var visit func(tree *TomlTree) visit = func(tree *TomlTree) { for _, key := range tree.Keys() { item := treeValue(tree, key) next.Fn(item) switch node := item.(type) { case *TomlTree: visit(node) case []*TomlTree: for _, subtree := range node { visit(subtree) } } } } visit(tree) } } } func processPath(path QueryPath, context interface{}) []interface{} { // terminate the path with a collection funciton result := []interface{}{} newPath := append(path, func(context interface{}, next QueryPath) { result = append(result, context) }) // execute the path newPath.Fn(context) return result }