1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
package api
import (
"fmt"
"strconv"
"strings"
)
const (
keyStart = '['
keyEnd = ']'
keySeparator = '='
)
func parseFields(opts *ApiOptions) (map[string]interface{}, error) {
params := make(map[string]interface{})
parseField := func(f string, isMagic bool) error {
var valueIndex int
var keystack []string
keyStartAt := 0
parseLoop:
for i, r := range f {
switch r {
case keyStart:
if keyStartAt == 0 {
keystack = append(keystack, f[0:i])
}
keyStartAt = i + 1
case keyEnd:
keystack = append(keystack, f[keyStartAt:i])
case keySeparator:
if keyStartAt == 0 {
keystack = append(keystack, f[0:i])
}
valueIndex = i + 1
break parseLoop
}
}
if len(keystack) == 0 {
return fmt.Errorf("invalid key: %q", f)
}
key := f
var value interface{} = nil
if valueIndex == 0 {
if keystack[len(keystack)-1] != "" {
return fmt.Errorf("field %q requires a value separated by an '=' sign", key)
}
} else {
key = f[0 : valueIndex-1]
value = f[valueIndex:]
}
if isMagic && value != nil {
var err error
value, err = magicFieldValue(value.(string), opts)
if err != nil {
return fmt.Errorf("error parsing %q value: %w", key, err)
}
}
destMap := params
isArray := false
var subkey string
for _, k := range keystack {
if k == "" {
isArray = true
continue
}
if subkey != "" {
var err error
if isArray {
destMap, err = addParamsSlice(destMap, subkey, k)
isArray = false
} else {
destMap, err = addParamsMap(destMap, subkey)
}
if err != nil {
return err
}
}
subkey = k
}
if isArray {
if value == nil {
destMap[subkey] = []interface{}{}
} else {
if v, exists := destMap[subkey]; exists {
if existSlice, ok := v.([]interface{}); ok {
destMap[subkey] = append(existSlice, value)
} else {
return fmt.Errorf("expected array type under %q, got %T", subkey, v)
}
} else {
destMap[subkey] = []interface{}{value}
}
}
} else {
destMap[subkey] = value
}
return nil
}
for _, f := range opts.RawFields {
if err := parseField(f, false); err != nil {
return params, err
}
}
for _, f := range opts.MagicFields {
if err := parseField(f, true); err != nil {
return params, err
}
}
return params, nil
}
func addParamsMap(m map[string]interface{}, key string) (map[string]interface{}, error) {
if v, exists := m[key]; exists {
if existMap, ok := v.(map[string]interface{}); ok {
return existMap, nil
} else {
return nil, fmt.Errorf("expected map type under %q, got %T", key, v)
}
}
newMap := make(map[string]interface{})
m[key] = newMap
return newMap, nil
}
func addParamsSlice(m map[string]interface{}, prevkey, newkey string) (map[string]interface{}, error) {
if v, exists := m[prevkey]; exists {
if existSlice, ok := v.([]interface{}); ok {
if len(existSlice) > 0 {
lastItem := existSlice[len(existSlice)-1]
if lastMap, ok := lastItem.(map[string]interface{}); ok {
if _, keyExists := lastMap[newkey]; !keyExists {
return lastMap, nil
}
}
}
newMap := make(map[string]interface{})
m[prevkey] = append(existSlice, newMap)
return newMap, nil
} else {
return nil, fmt.Errorf("expected array type under %q, got %T", prevkey, v)
}
}
newMap := make(map[string]interface{})
m[prevkey] = []interface{}{newMap}
return newMap, nil
}
func magicFieldValue(v string, opts *ApiOptions) (interface{}, error) {
if strings.HasPrefix(v, "@") {
b, err := opts.IO.ReadUserFile(v[1:])
if err != nil {
return "", err
}
return string(b), nil
}
if n, err := strconv.Atoi(v); err == nil {
return n, nil
}
switch v {
case "true":
return true, nil
case "false":
return false, nil
case "null":
return nil, nil
default:
return fillPlaceholders(v, opts)
}
}
|