meta.go 3.1 KB

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