github.com/BTBurke/caddy-jwt@v3.7.1+incompatible/flatten.go (about) 1 // Flatten makes flat, one-dimensional maps from arbitrarily nested ones. 2 // 3 // Map keys turn into compound 4 // names, like `a.b.1.c` (dotted style) or `a[b][1][c]` (Rails style). It takes input as either JSON strings or 5 // Go structures. It (only) knows how to traverse JSON types: maps, slices and scalars. 6 // 7 // Or Go maps directly. 8 // 9 // t := map[string]interface{}{ 10 // "a": "b", 11 // "c": map[string]interface{}{ 12 // "d": "e", 13 // "f": "g", 14 // }, 15 // "z": 1.4567, 16 // } 17 // 18 // flat, err := Flatten(nested, "", RailsStyle) 19 // 20 // // output: 21 // // map[string]interface{}{ 22 // // "a": "b", 23 // // "c[d]": "e", 24 // // "c[f]": "g", 25 // // "z": 1.4567, 26 // // } 27 // 28 package jwt 29 30 import "errors" 31 32 // The presentation style of keys. 33 type SeparatorStyle int 34 35 const ( 36 _ SeparatorStyle = iota 37 38 // Separate nested key components with dots, e.g. "a.b.1.c.d" 39 DotStyle 40 41 // Separate ala Rails, e.g. "a[b][c][1][d]" 42 RailsStyle 43 ) 44 45 // Nested input must be a map or slice 46 var NotValidInputError = errors.New("Not a valid input: map or slice") 47 48 // Flatten generates a flat map from a nested one. The original may include values of type map, slice and scalar, 49 // but not struct. Keys in the flat map will be a compound of descending map keys and slice iterations. 50 // The presentation of keys is set by style. A prefix is joined to each key. 51 func Flatten(nested map[string]interface{}, prefix string, style SeparatorStyle) (map[string]interface{}, error) { 52 flatmap := make(map[string]interface{}) 53 54 err := flatten(true, flatmap, nested, prefix, style) 55 if err != nil { 56 return nil, err 57 } 58 59 return flatmap, nil 60 } 61 62 func flatten(top bool, flatMap map[string]interface{}, nested interface{}, prefix string, style SeparatorStyle) error { 63 assign := func(newKey string, v interface{}) error { 64 switch v.(type) { 65 case map[string]interface{}: 66 if err := flatten(false, flatMap, v, newKey, style); err != nil { 67 return err 68 } 69 default: 70 flatMap[newKey] = v 71 } 72 73 return nil 74 } 75 76 switch nested.(type) { 77 case map[string]interface{}: 78 for k, v := range nested.(map[string]interface{}) { 79 newKey := enkey(top, prefix, k, style) 80 assign(newKey, v) 81 } 82 default: 83 return NotValidInputError 84 } 85 86 return nil 87 } 88 89 func enkey(top bool, prefix, subkey string, style SeparatorStyle) string { 90 key := prefix 91 92 if top { 93 key += subkey 94 } else { 95 switch style { 96 case DotStyle: 97 key += "." + subkey 98 case RailsStyle: 99 key += "[" + subkey + "]" 100 } 101 } 102 103 return key 104 }