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  }