yaml.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. // Copyright 2015 go-swagger maintainers
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package swag
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "path/filepath"
  19. "strconv"
  20. "github.com/mailru/easyjson/jlexer"
  21. "github.com/mailru/easyjson/jwriter"
  22. yaml "gopkg.in/yaml.v2"
  23. )
  24. // YAMLMatcher matches yaml
  25. func YAMLMatcher(path string) bool {
  26. ext := filepath.Ext(path)
  27. return ext == ".yaml" || ext == ".yml"
  28. }
  29. // YAMLToJSON converts YAML unmarshaled data into json compatible data
  30. func YAMLToJSON(data interface{}) (json.RawMessage, error) {
  31. jm, err := transformData(data)
  32. if err != nil {
  33. return nil, err
  34. }
  35. b, err := WriteJSON(jm)
  36. return json.RawMessage(b), err
  37. }
  38. // BytesToYAMLDoc converts a byte slice into a YAML document
  39. func BytesToYAMLDoc(data []byte) (interface{}, error) {
  40. var canary map[interface{}]interface{} // validate this is an object and not a different type
  41. if err := yaml.Unmarshal(data, &canary); err != nil {
  42. return nil, err
  43. }
  44. var document yaml.MapSlice // preserve order that is present in the document
  45. if err := yaml.Unmarshal(data, &document); err != nil {
  46. return nil, err
  47. }
  48. return document, nil
  49. }
  50. // JSONMapSlice represent a JSON object, with the order of keys maintained
  51. type JSONMapSlice []JSONMapItem
  52. // MarshalJSON renders a JSONMapSlice as JSON
  53. func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
  54. w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
  55. s.MarshalEasyJSON(w)
  56. return w.BuildBytes()
  57. }
  58. // MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
  59. func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {
  60. w.RawByte('{')
  61. ln := len(s)
  62. last := ln - 1
  63. for i := 0; i < ln; i++ {
  64. s[i].MarshalEasyJSON(w)
  65. if i != last { // last item
  66. w.RawByte(',')
  67. }
  68. }
  69. w.RawByte('}')
  70. }
  71. // UnmarshalJSON makes a JSONMapSlice from JSON
  72. func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
  73. l := jlexer.Lexer{Data: data}
  74. s.UnmarshalEasyJSON(&l)
  75. return l.Error()
  76. }
  77. // UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
  78. func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
  79. if in.IsNull() {
  80. in.Skip()
  81. return
  82. }
  83. var result JSONMapSlice
  84. in.Delim('{')
  85. for !in.IsDelim('}') {
  86. var mi JSONMapItem
  87. mi.UnmarshalEasyJSON(in)
  88. result = append(result, mi)
  89. }
  90. *s = result
  91. }
  92. // JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
  93. type JSONMapItem struct {
  94. Key string
  95. Value interface{}
  96. }
  97. // MarshalJSON renders a JSONMapItem as JSON
  98. func (s JSONMapItem) MarshalJSON() ([]byte, error) {
  99. w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
  100. s.MarshalEasyJSON(w)
  101. return w.BuildBytes()
  102. }
  103. // MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
  104. func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
  105. w.String(s.Key)
  106. w.RawByte(':')
  107. w.Raw(WriteJSON(s.Value))
  108. }
  109. // UnmarshalJSON makes a JSONMapItem from JSON
  110. func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
  111. l := jlexer.Lexer{Data: data}
  112. s.UnmarshalEasyJSON(&l)
  113. return l.Error()
  114. }
  115. // UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
  116. func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
  117. key := in.UnsafeString()
  118. in.WantColon()
  119. value := in.Interface()
  120. in.WantComma()
  121. s.Key = key
  122. s.Value = value
  123. }
  124. func transformData(input interface{}) (out interface{}, err error) {
  125. format := func(t interface{}) (string, error) {
  126. switch k := t.(type) {
  127. case string:
  128. return k, nil
  129. case uint:
  130. return strconv.FormatUint(uint64(k), 10), nil
  131. case uint8:
  132. return strconv.FormatUint(uint64(k), 10), nil
  133. case uint16:
  134. return strconv.FormatUint(uint64(k), 10), nil
  135. case uint32:
  136. return strconv.FormatUint(uint64(k), 10), nil
  137. case uint64:
  138. return strconv.FormatUint(k, 10), nil
  139. case int:
  140. return strconv.Itoa(k), nil
  141. case int8:
  142. return strconv.FormatInt(int64(k), 10), nil
  143. case int16:
  144. return strconv.FormatInt(int64(k), 10), nil
  145. case int32:
  146. return strconv.FormatInt(int64(k), 10), nil
  147. case int64:
  148. return strconv.FormatInt(k, 10), nil
  149. default:
  150. return "", fmt.Errorf("unexpected map key type, got: %T", k)
  151. }
  152. }
  153. switch in := input.(type) {
  154. case yaml.MapSlice:
  155. o := make(JSONMapSlice, len(in))
  156. for i, mi := range in {
  157. var nmi JSONMapItem
  158. if nmi.Key, err = format(mi.Key); err != nil {
  159. return nil, err
  160. }
  161. v, ert := transformData(mi.Value)
  162. if ert != nil {
  163. return nil, ert
  164. }
  165. nmi.Value = v
  166. o[i] = nmi
  167. }
  168. return o, nil
  169. case map[interface{}]interface{}:
  170. o := make(JSONMapSlice, 0, len(in))
  171. for ke, va := range in {
  172. var nmi JSONMapItem
  173. if nmi.Key, err = format(ke); err != nil {
  174. return nil, err
  175. }
  176. v, ert := transformData(va)
  177. if ert != nil {
  178. return nil, ert
  179. }
  180. nmi.Value = v
  181. o = append(o, nmi)
  182. }
  183. return o, nil
  184. case []interface{}:
  185. len1 := len(in)
  186. o := make([]interface{}, len1)
  187. for i := 0; i < len1; i++ {
  188. o[i], err = transformData(in[i])
  189. if err != nil {
  190. return nil, err
  191. }
  192. }
  193. return o, nil
  194. }
  195. return input, nil
  196. }
  197. // YAMLDoc loads a yaml document from either http or a file and converts it to json
  198. func YAMLDoc(path string) (json.RawMessage, error) {
  199. yamlDoc, err := YAMLData(path)
  200. if err != nil {
  201. return nil, err
  202. }
  203. data, err := YAMLToJSON(yamlDoc)
  204. if err != nil {
  205. return nil, err
  206. }
  207. return data, nil
  208. }
  209. // YAMLData loads a yaml document from either http or a file
  210. func YAMLData(path string) (interface{}, error) {
  211. data, err := LoadFromFileOrHTTP(path)
  212. if err != nil {
  213. return nil, err
  214. }
  215. return BytesToYAMLDoc(data)
  216. }