You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.1 KiB

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