123 lines
3.0 KiB
Go
123 lines
3.0 KiB
Go
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
|
|
}
|