main.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. // Command toml-test-encoder satisfies the toml-test interface for testing
  2. // TOML encoders. Namely, it accepts JSON on stdin and outputs TOML on stdout.
  3. package main
  4. import (
  5. "encoding/json"
  6. "flag"
  7. "log"
  8. "os"
  9. "path"
  10. "strconv"
  11. "time"
  12. "github.com/BurntSushi/toml"
  13. )
  14. func init() {
  15. log.SetFlags(0)
  16. flag.Usage = usage
  17. flag.Parse()
  18. }
  19. func usage() {
  20. log.Printf("Usage: %s < json-file\n", path.Base(os.Args[0]))
  21. flag.PrintDefaults()
  22. os.Exit(1)
  23. }
  24. func main() {
  25. if flag.NArg() != 0 {
  26. flag.Usage()
  27. }
  28. var tmp interface{}
  29. if err := json.NewDecoder(os.Stdin).Decode(&tmp); err != nil {
  30. log.Fatalf("Error decoding JSON: %s", err)
  31. }
  32. tomlData := translate(tmp)
  33. if err := toml.NewEncoder(os.Stdout).Encode(tomlData); err != nil {
  34. log.Fatalf("Error encoding TOML: %s", err)
  35. }
  36. }
  37. func translate(typedJson interface{}) interface{} {
  38. switch v := typedJson.(type) {
  39. case map[string]interface{}:
  40. if len(v) == 2 && in("type", v) && in("value", v) {
  41. return untag(v)
  42. }
  43. m := make(map[string]interface{}, len(v))
  44. for k, v2 := range v {
  45. m[k] = translate(v2)
  46. }
  47. return m
  48. case []interface{}:
  49. tabArray := make([]map[string]interface{}, len(v))
  50. for i := range v {
  51. if m, ok := translate(v[i]).(map[string]interface{}); ok {
  52. tabArray[i] = m
  53. } else {
  54. log.Fatalf("JSON arrays may only contain objects. This " +
  55. "corresponds to only tables being allowed in " +
  56. "TOML table arrays.")
  57. }
  58. }
  59. return tabArray
  60. }
  61. log.Fatalf("Unrecognized JSON format '%T'.", typedJson)
  62. panic("unreachable")
  63. }
  64. func untag(typed map[string]interface{}) interface{} {
  65. t := typed["type"].(string)
  66. v := typed["value"]
  67. switch t {
  68. case "string":
  69. return v.(string)
  70. case "integer":
  71. v := v.(string)
  72. n, err := strconv.Atoi(v)
  73. if err != nil {
  74. log.Fatalf("Could not parse '%s' as integer: %s", v, err)
  75. }
  76. return n
  77. case "float":
  78. v := v.(string)
  79. f, err := strconv.ParseFloat(v, 64)
  80. if err != nil {
  81. log.Fatalf("Could not parse '%s' as float64: %s", v, err)
  82. }
  83. return f
  84. case "datetime":
  85. v := v.(string)
  86. t, err := time.Parse("2006-01-02T15:04:05Z", v)
  87. if err != nil {
  88. log.Fatalf("Could not parse '%s' as a datetime: %s", v, err)
  89. }
  90. return t
  91. case "bool":
  92. v := v.(string)
  93. switch v {
  94. case "true":
  95. return true
  96. case "false":
  97. return false
  98. }
  99. log.Fatalf("Could not parse '%s' as a boolean.", v)
  100. case "array":
  101. v := v.([]interface{})
  102. array := make([]interface{}, len(v))
  103. for i := range v {
  104. if m, ok := v[i].(map[string]interface{}); ok {
  105. array[i] = untag(m)
  106. } else {
  107. log.Fatalf("Arrays may only contain other arrays or "+
  108. "primitive values, but found a '%T'.", m)
  109. }
  110. }
  111. return array
  112. }
  113. log.Fatalf("Unrecognized tag type '%s'.", t)
  114. panic("unreachable")
  115. }
  116. func in(key string, m map[string]interface{}) bool {
  117. _, ok := m[key]
  118. return ok
  119. }