yaml.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  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. "errors"
  18. "fmt"
  19. "path/filepath"
  20. "reflect"
  21. "sort"
  22. "strconv"
  23. "github.com/mailru/easyjson/jlexer"
  24. "github.com/mailru/easyjson/jwriter"
  25. yaml "gopkg.in/yaml.v3"
  26. )
  27. // YAMLMatcher matches yaml
  28. func YAMLMatcher(path string) bool {
  29. ext := filepath.Ext(path)
  30. return ext == ".yaml" || ext == ".yml"
  31. }
  32. // YAMLToJSON converts YAML unmarshaled data into json compatible data
  33. func YAMLToJSON(data interface{}) (json.RawMessage, error) {
  34. jm, err := transformData(data)
  35. if err != nil {
  36. return nil, err
  37. }
  38. b, err := WriteJSON(jm)
  39. return json.RawMessage(b), err
  40. }
  41. // BytesToYAMLDoc converts a byte slice into a YAML document
  42. func BytesToYAMLDoc(data []byte) (interface{}, error) {
  43. var document yaml.Node // preserve order that is present in the document
  44. if err := yaml.Unmarshal(data, &document); err != nil {
  45. return nil, err
  46. }
  47. if document.Kind != yaml.DocumentNode || len(document.Content) != 1 || document.Content[0].Kind != yaml.MappingNode {
  48. return nil, errors.New("only YAML documents that are objects are supported")
  49. }
  50. return &document, nil
  51. }
  52. func yamlNode(root *yaml.Node) (interface{}, error) {
  53. switch root.Kind {
  54. case yaml.DocumentNode:
  55. return yamlDocument(root)
  56. case yaml.SequenceNode:
  57. return yamlSequence(root)
  58. case yaml.MappingNode:
  59. return yamlMapping(root)
  60. case yaml.ScalarNode:
  61. return yamlScalar(root)
  62. case yaml.AliasNode:
  63. return yamlNode(root.Alias)
  64. default:
  65. return nil, fmt.Errorf("unsupported YAML node type: %v", root.Kind)
  66. }
  67. }
  68. func yamlDocument(node *yaml.Node) (interface{}, error) {
  69. if len(node.Content) != 1 {
  70. return nil, fmt.Errorf("unexpected YAML Document node content length: %d", len(node.Content))
  71. }
  72. return yamlNode(node.Content[0])
  73. }
  74. func yamlMapping(node *yaml.Node) (interface{}, error) {
  75. m := make(JSONMapSlice, len(node.Content)/2)
  76. var j int
  77. for i := 0; i < len(node.Content); i += 2 {
  78. var nmi JSONMapItem
  79. k, err := yamlStringScalarC(node.Content[i])
  80. if err != nil {
  81. return nil, fmt.Errorf("unable to decode YAML map key: %w", err)
  82. }
  83. nmi.Key = k
  84. v, err := yamlNode(node.Content[i+1])
  85. if err != nil {
  86. return nil, fmt.Errorf("unable to process YAML map value for key %q: %w", k, err)
  87. }
  88. nmi.Value = v
  89. m[j] = nmi
  90. j++
  91. }
  92. return m, nil
  93. }
  94. func yamlSequence(node *yaml.Node) (interface{}, error) {
  95. s := make([]interface{}, 0)
  96. for i := 0; i < len(node.Content); i++ {
  97. v, err := yamlNode(node.Content[i])
  98. if err != nil {
  99. return nil, fmt.Errorf("unable to decode YAML sequence value: %w", err)
  100. }
  101. s = append(s, v)
  102. }
  103. return s, nil
  104. }
  105. const ( // See https://yaml.org/type/
  106. yamlStringScalar = "tag:yaml.org,2002:str"
  107. yamlIntScalar = "tag:yaml.org,2002:int"
  108. yamlBoolScalar = "tag:yaml.org,2002:bool"
  109. yamlFloatScalar = "tag:yaml.org,2002:float"
  110. yamlTimestamp = "tag:yaml.org,2002:timestamp"
  111. yamlNull = "tag:yaml.org,2002:null"
  112. )
  113. func yamlScalar(node *yaml.Node) (interface{}, error) {
  114. switch node.LongTag() {
  115. case yamlStringScalar:
  116. return node.Value, nil
  117. case yamlBoolScalar:
  118. b, err := strconv.ParseBool(node.Value)
  119. if err != nil {
  120. return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting bool content: %w", node.Value, err)
  121. }
  122. return b, nil
  123. case yamlIntScalar:
  124. i, err := strconv.ParseInt(node.Value, 10, 64)
  125. if err != nil {
  126. return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting integer content: %w", node.Value, err)
  127. }
  128. return i, nil
  129. case yamlFloatScalar:
  130. f, err := strconv.ParseFloat(node.Value, 64)
  131. if err != nil {
  132. return nil, fmt.Errorf("unable to process scalar node. Got %q. Expecting float content: %w", node.Value, err)
  133. }
  134. return f, nil
  135. case yamlTimestamp:
  136. return node.Value, nil
  137. case yamlNull:
  138. return nil, nil //nolint:nilnil
  139. default:
  140. return nil, fmt.Errorf("YAML tag %q is not supported", node.LongTag())
  141. }
  142. }
  143. func yamlStringScalarC(node *yaml.Node) (string, error) {
  144. if node.Kind != yaml.ScalarNode {
  145. return "", fmt.Errorf("expecting a string scalar but got %q", node.Kind)
  146. }
  147. switch node.LongTag() {
  148. case yamlStringScalar, yamlIntScalar, yamlFloatScalar:
  149. return node.Value, nil
  150. default:
  151. return "", fmt.Errorf("YAML tag %q is not supported as map key", node.LongTag())
  152. }
  153. }
  154. // JSONMapSlice represent a JSON object, with the order of keys maintained
  155. type JSONMapSlice []JSONMapItem
  156. // MarshalJSON renders a JSONMapSlice as JSON
  157. func (s JSONMapSlice) MarshalJSON() ([]byte, error) {
  158. w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
  159. s.MarshalEasyJSON(w)
  160. return w.BuildBytes()
  161. }
  162. // MarshalEasyJSON renders a JSONMapSlice as JSON, using easyJSON
  163. func (s JSONMapSlice) MarshalEasyJSON(w *jwriter.Writer) {
  164. w.RawByte('{')
  165. ln := len(s)
  166. last := ln - 1
  167. for i := 0; i < ln; i++ {
  168. s[i].MarshalEasyJSON(w)
  169. if i != last { // last item
  170. w.RawByte(',')
  171. }
  172. }
  173. w.RawByte('}')
  174. }
  175. // UnmarshalJSON makes a JSONMapSlice from JSON
  176. func (s *JSONMapSlice) UnmarshalJSON(data []byte) error {
  177. l := jlexer.Lexer{Data: data}
  178. s.UnmarshalEasyJSON(&l)
  179. return l.Error()
  180. }
  181. // UnmarshalEasyJSON makes a JSONMapSlice from JSON, using easyJSON
  182. func (s *JSONMapSlice) UnmarshalEasyJSON(in *jlexer.Lexer) {
  183. if in.IsNull() {
  184. in.Skip()
  185. return
  186. }
  187. var result JSONMapSlice
  188. in.Delim('{')
  189. for !in.IsDelim('}') {
  190. var mi JSONMapItem
  191. mi.UnmarshalEasyJSON(in)
  192. result = append(result, mi)
  193. }
  194. *s = result
  195. }
  196. func (s JSONMapSlice) MarshalYAML() (interface{}, error) {
  197. var n yaml.Node
  198. n.Kind = yaml.DocumentNode
  199. var nodes []*yaml.Node
  200. for _, item := range s {
  201. nn, err := json2yaml(item.Value)
  202. if err != nil {
  203. return nil, err
  204. }
  205. ns := []*yaml.Node{
  206. {
  207. Kind: yaml.ScalarNode,
  208. Tag: yamlStringScalar,
  209. Value: item.Key,
  210. },
  211. nn,
  212. }
  213. nodes = append(nodes, ns...)
  214. }
  215. n.Content = []*yaml.Node{
  216. {
  217. Kind: yaml.MappingNode,
  218. Content: nodes,
  219. },
  220. }
  221. return yaml.Marshal(&n)
  222. }
  223. func isNil(input interface{}) bool {
  224. if input == nil {
  225. return true
  226. }
  227. kind := reflect.TypeOf(input).Kind()
  228. switch kind { //nolint:exhaustive
  229. case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
  230. return reflect.ValueOf(input).IsNil()
  231. default:
  232. return false
  233. }
  234. }
  235. func json2yaml(item interface{}) (*yaml.Node, error) {
  236. if isNil(item) {
  237. return &yaml.Node{
  238. Kind: yaml.ScalarNode,
  239. Value: "null",
  240. }, nil
  241. }
  242. switch val := item.(type) {
  243. case JSONMapSlice:
  244. var n yaml.Node
  245. n.Kind = yaml.MappingNode
  246. for i := range val {
  247. childNode, err := json2yaml(&val[i].Value)
  248. if err != nil {
  249. return nil, err
  250. }
  251. n.Content = append(n.Content, &yaml.Node{
  252. Kind: yaml.ScalarNode,
  253. Tag: yamlStringScalar,
  254. Value: val[i].Key,
  255. }, childNode)
  256. }
  257. return &n, nil
  258. case map[string]interface{}:
  259. var n yaml.Node
  260. n.Kind = yaml.MappingNode
  261. keys := make([]string, 0, len(val))
  262. for k := range val {
  263. keys = append(keys, k)
  264. }
  265. sort.Strings(keys)
  266. for _, k := range keys {
  267. v := val[k]
  268. childNode, err := json2yaml(v)
  269. if err != nil {
  270. return nil, err
  271. }
  272. n.Content = append(n.Content, &yaml.Node{
  273. Kind: yaml.ScalarNode,
  274. Tag: yamlStringScalar,
  275. Value: k,
  276. }, childNode)
  277. }
  278. return &n, nil
  279. case []interface{}:
  280. var n yaml.Node
  281. n.Kind = yaml.SequenceNode
  282. for i := range val {
  283. childNode, err := json2yaml(val[i])
  284. if err != nil {
  285. return nil, err
  286. }
  287. n.Content = append(n.Content, childNode)
  288. }
  289. return &n, nil
  290. case string:
  291. return &yaml.Node{
  292. Kind: yaml.ScalarNode,
  293. Tag: yamlStringScalar,
  294. Value: val,
  295. }, nil
  296. case float64:
  297. return &yaml.Node{
  298. Kind: yaml.ScalarNode,
  299. Tag: yamlFloatScalar,
  300. Value: strconv.FormatFloat(val, 'f', -1, 64),
  301. }, nil
  302. case int64:
  303. return &yaml.Node{
  304. Kind: yaml.ScalarNode,
  305. Tag: yamlIntScalar,
  306. Value: strconv.FormatInt(val, 10),
  307. }, nil
  308. case uint64:
  309. return &yaml.Node{
  310. Kind: yaml.ScalarNode,
  311. Tag: yamlIntScalar,
  312. Value: strconv.FormatUint(val, 10),
  313. }, nil
  314. case bool:
  315. return &yaml.Node{
  316. Kind: yaml.ScalarNode,
  317. Tag: yamlBoolScalar,
  318. Value: strconv.FormatBool(val),
  319. }, nil
  320. default:
  321. return nil, fmt.Errorf("unhandled type: %T", val)
  322. }
  323. }
  324. // JSONMapItem represents the value of a key in a JSON object held by JSONMapSlice
  325. type JSONMapItem struct {
  326. Key string
  327. Value interface{}
  328. }
  329. // MarshalJSON renders a JSONMapItem as JSON
  330. func (s JSONMapItem) MarshalJSON() ([]byte, error) {
  331. w := &jwriter.Writer{Flags: jwriter.NilMapAsEmpty | jwriter.NilSliceAsEmpty}
  332. s.MarshalEasyJSON(w)
  333. return w.BuildBytes()
  334. }
  335. // MarshalEasyJSON renders a JSONMapItem as JSON, using easyJSON
  336. func (s JSONMapItem) MarshalEasyJSON(w *jwriter.Writer) {
  337. w.String(s.Key)
  338. w.RawByte(':')
  339. w.Raw(WriteJSON(s.Value))
  340. }
  341. // UnmarshalJSON makes a JSONMapItem from JSON
  342. func (s *JSONMapItem) UnmarshalJSON(data []byte) error {
  343. l := jlexer.Lexer{Data: data}
  344. s.UnmarshalEasyJSON(&l)
  345. return l.Error()
  346. }
  347. // UnmarshalEasyJSON makes a JSONMapItem from JSON, using easyJSON
  348. func (s *JSONMapItem) UnmarshalEasyJSON(in *jlexer.Lexer) {
  349. key := in.UnsafeString()
  350. in.WantColon()
  351. value := in.Interface()
  352. in.WantComma()
  353. s.Key = key
  354. s.Value = value
  355. }
  356. func transformData(input interface{}) (out interface{}, err error) {
  357. format := func(t interface{}) (string, error) {
  358. switch k := t.(type) {
  359. case string:
  360. return k, nil
  361. case uint:
  362. return strconv.FormatUint(uint64(k), 10), nil
  363. case uint8:
  364. return strconv.FormatUint(uint64(k), 10), nil
  365. case uint16:
  366. return strconv.FormatUint(uint64(k), 10), nil
  367. case uint32:
  368. return strconv.FormatUint(uint64(k), 10), nil
  369. case uint64:
  370. return strconv.FormatUint(k, 10), nil
  371. case int:
  372. return strconv.Itoa(k), nil
  373. case int8:
  374. return strconv.FormatInt(int64(k), 10), nil
  375. case int16:
  376. return strconv.FormatInt(int64(k), 10), nil
  377. case int32:
  378. return strconv.FormatInt(int64(k), 10), nil
  379. case int64:
  380. return strconv.FormatInt(k, 10), nil
  381. default:
  382. return "", fmt.Errorf("unexpected map key type, got: %T", k)
  383. }
  384. }
  385. switch in := input.(type) {
  386. case yaml.Node:
  387. return yamlNode(&in)
  388. case *yaml.Node:
  389. return yamlNode(in)
  390. case map[interface{}]interface{}:
  391. o := make(JSONMapSlice, 0, len(in))
  392. for ke, va := range in {
  393. var nmi JSONMapItem
  394. if nmi.Key, err = format(ke); err != nil {
  395. return nil, err
  396. }
  397. v, ert := transformData(va)
  398. if ert != nil {
  399. return nil, ert
  400. }
  401. nmi.Value = v
  402. o = append(o, nmi)
  403. }
  404. return o, nil
  405. case []interface{}:
  406. len1 := len(in)
  407. o := make([]interface{}, len1)
  408. for i := 0; i < len1; i++ {
  409. o[i], err = transformData(in[i])
  410. if err != nil {
  411. return nil, err
  412. }
  413. }
  414. return o, nil
  415. }
  416. return input, nil
  417. }
  418. // YAMLDoc loads a yaml document from either http or a file and converts it to json
  419. func YAMLDoc(path string) (json.RawMessage, error) {
  420. yamlDoc, err := YAMLData(path)
  421. if err != nil {
  422. return nil, err
  423. }
  424. data, err := YAMLToJSON(yamlDoc)
  425. if err != nil {
  426. return nil, err
  427. }
  428. return data, nil
  429. }
  430. // YAMLData loads a yaml document from either http or a file
  431. func YAMLData(path string) (interface{}, error) {
  432. data, err := LoadFromFileOrHTTP(path)
  433. if err != nil {
  434. return nil, err
  435. }
  436. return BytesToYAMLDoc(data)
  437. }