git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/toml/meta.go (about)

     1  package toml
     2  
     3  import (
     4  	"strings"
     5  )
     6  
     7  // MetaData allows access to meta information about TOML data that's not
     8  // accessible otherwise.
     9  //
    10  // It allows checking if a key is defined in the TOML data, whether any keys
    11  // were undecoded, and the TOML type of a key.
    12  type MetaData struct {
    13  	context Key // Used only during decoding.
    14  
    15  	keyInfo map[string]keyInfo
    16  	mapping map[string]interface{}
    17  	keys    []Key
    18  	decoded map[string]struct{}
    19  	data    []byte // Input file; for errors.
    20  }
    21  
    22  // IsDefined reports if the key exists in the TOML data.
    23  //
    24  // The key should be specified hierarchically, for example to access the TOML
    25  // key "a.b.c" you would use IsDefined("a", "b", "c"). Keys are case sensitive.
    26  //
    27  // Returns false for an empty key.
    28  func (md *MetaData) IsDefined(key ...string) bool {
    29  	if len(key) == 0 {
    30  		return false
    31  	}
    32  
    33  	var (
    34  		hash      map[string]interface{}
    35  		ok        bool
    36  		hashOrVal interface{} = md.mapping
    37  	)
    38  	for _, k := range key {
    39  		if hash, ok = hashOrVal.(map[string]interface{}); !ok {
    40  			return false
    41  		}
    42  		if hashOrVal, ok = hash[k]; !ok {
    43  			return false
    44  		}
    45  	}
    46  	return true
    47  }
    48  
    49  // Type returns a string representation of the type of the key specified.
    50  //
    51  // Type will return the empty string if given an empty key or a key that does
    52  // not exist. Keys are case sensitive.
    53  func (md *MetaData) Type(key ...string) string {
    54  	if ki, ok := md.keyInfo[Key(key).String()]; ok {
    55  		return ki.tomlType.typeString()
    56  	}
    57  	return ""
    58  }
    59  
    60  // Keys returns a slice of every key in the TOML data, including key groups.
    61  //
    62  // Each key is itself a slice, where the first element is the top of the
    63  // hierarchy and the last is the most specific. The list will have the same
    64  // order as the keys appeared in the TOML data.
    65  //
    66  // All keys returned are non-empty.
    67  func (md *MetaData) Keys() []Key {
    68  	return md.keys
    69  }
    70  
    71  // Undecoded returns all keys that have not been decoded in the order in which
    72  // they appear in the original TOML document.
    73  //
    74  // This includes keys that haven't been decoded because of a Primitive value.
    75  // Once the Primitive value is decoded, the keys will be considered decoded.
    76  //
    77  // Also note that decoding into an empty interface will result in no decoding,
    78  // and so no keys will be considered decoded.
    79  //
    80  // In this sense, the Undecoded keys correspond to keys in the TOML document
    81  // that do not have a concrete type in your representation.
    82  func (md *MetaData) Undecoded() []Key {
    83  	undecoded := make([]Key, 0, len(md.keys))
    84  	for _, key := range md.keys {
    85  		if _, ok := md.decoded[key.String()]; !ok {
    86  			undecoded = append(undecoded, key)
    87  		}
    88  	}
    89  	return undecoded
    90  }
    91  
    92  // Key represents any TOML key, including key groups. Use (MetaData).Keys to get
    93  // values of this type.
    94  type Key []string
    95  
    96  func (k Key) String() string {
    97  	ss := make([]string, len(k))
    98  	for i := range k {
    99  		ss[i] = k.maybeQuoted(i)
   100  	}
   101  	return strings.Join(ss, ".")
   102  }
   103  
   104  func (k Key) maybeQuoted(i int) string {
   105  	if k[i] == "" {
   106  		return `""`
   107  	}
   108  	for _, c := range k[i] {
   109  		if !isBareKeyChar(c) {
   110  			return `"` + dblQuotedReplacer.Replace(k[i]) + `"`
   111  		}
   112  	}
   113  	return k[i]
   114  }
   115  
   116  func (k Key) add(piece string) Key {
   117  	newKey := make(Key, len(k)+1)
   118  	copy(newKey, k)
   119  	newKey[len(k)] = piece
   120  	return newKey
   121  }