| package jpath |
| |
| import ( |
| . "github.com/pelletier/go-toml" |
| ) |
| |
| type PathFn func(context interface{}) []interface{} |
| |
| func treeValue(tree *TomlTree, key string) interface{} { |
| return tree.GetPath([]string{key}) |
| } |
| |
| func matchKeyFn(name string) PathFn { |
| return func(context interface{}) []interface{} { |
| if tree, ok := context.(*TomlTree); ok { |
| item := treeValue(tree, name) |
| if item != nil { |
| return []interface{}{ item } |
| } |
| } |
| return []interface{}{} |
| } |
| } |
| |
| func matchIndexFn(idx int) PathFn { |
| return func(context interface{}) []interface{} { |
| if arr, ok := context.([]interface{}); ok { |
| if idx < len(arr) && idx >= 0 { |
| return arr[idx:idx+1] |
| } |
| } |
| return []interface{}{} |
| } |
| } |
| |
| func matchSliceFn(start, end, step int) PathFn { |
| return func(context interface{}) []interface{} { |
| result := []interface{}{} |
| 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 { |
| result = append(result, arr[idx]) |
| } |
| } |
| return result |
| } |
| } |
| |
| func matchAnyFn() PathFn { |
| return func(context interface{}) []interface{} { |
| result := []interface{}{} |
| if tree, ok := context.(*TomlTree); ok { |
| for _, key := range tree.Keys() { |
| item := treeValue(tree, key) |
| result = append(result, item) |
| } |
| } |
| return result |
| } |
| } |
| |
| func matchUnionFn(union []PathFn) PathFn { |
| return func(context interface{}) []interface{} { |
| result := []interface{}{} |
| for _, fn := range union { |
| result = append(result, fn(context)...) |
| } |
| return result |
| } |
| } |
| |
| func matchRecurseFn() PathFn { |
| return func(context interface{}) []interface{} { |
| result := []interface{}{ context } |
| |
| if tree, ok := context.(*TomlTree); ok { |
| var visit func(tree *TomlTree) |
| visit = func(tree *TomlTree) { |
| for _, key := range tree.Keys() { |
| item := treeValue(tree, key) |
| result = append(result, item) |
| switch node := item.(type) { |
| case *TomlTree: |
| visit(node) |
| case []*TomlTree: |
| for _, subtree := range node { |
| visit(subtree) |
| } |
| } |
| } |
| } |
| visit(tree) |
| } |
| return result |
| } |
| } |
| |
| func processPath(path []PathFn, context interface{}) []interface{} { |
| result := []interface{}{ context } // start with the root |
| for _, fn := range path { |
| next := []interface{}{} |
| for _, ctx := range result { |
| next = append(next, fn(ctx)...) |
| } |
| if len(next) == 0 { |
| return next // exit if there is nothing more to search |
| } |
| result = next // prep the next iteration |
| } |
| return result |
| } |