writer.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Copyright 2017 Google LLC. All Rights Reserved.
  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 jsonschema
  15. import (
  16. "fmt"
  17. "gopkg.in/yaml.v3"
  18. )
  19. const indentation = " "
  20. func renderMappingNode(node *yaml.Node, indent string) (result string) {
  21. result = "{\n"
  22. innerIndent := indent + indentation
  23. for i := 0; i < len(node.Content); i += 2 {
  24. // first print the key
  25. key := node.Content[i].Value
  26. result += fmt.Sprintf("%s\"%+v\": ", innerIndent, key)
  27. // then the value
  28. value := node.Content[i+1]
  29. switch value.Kind {
  30. case yaml.ScalarNode:
  31. result += "\"" + value.Value + "\""
  32. case yaml.MappingNode:
  33. result += renderMappingNode(value, innerIndent)
  34. case yaml.SequenceNode:
  35. result += renderSequenceNode(value, innerIndent)
  36. default:
  37. result += fmt.Sprintf("???MapItem(Key:%+v, Value:%T)", value, value)
  38. }
  39. if i < len(node.Content)-2 {
  40. result += ","
  41. }
  42. result += "\n"
  43. }
  44. result += indent + "}"
  45. return result
  46. }
  47. func renderSequenceNode(node *yaml.Node, indent string) (result string) {
  48. result = "[\n"
  49. innerIndent := indent + indentation
  50. for i := 0; i < len(node.Content); i++ {
  51. item := node.Content[i]
  52. switch item.Kind {
  53. case yaml.ScalarNode:
  54. result += innerIndent + "\"" + item.Value + "\""
  55. case yaml.MappingNode:
  56. result += innerIndent + renderMappingNode(item, innerIndent) + ""
  57. default:
  58. result += innerIndent + fmt.Sprintf("???ArrayItem(%+v)", item)
  59. }
  60. if i < len(node.Content)-1 {
  61. result += ","
  62. }
  63. result += "\n"
  64. }
  65. result += indent + "]"
  66. return result
  67. }
  68. func renderStringArray(array []string, indent string) (result string) {
  69. result = "[\n"
  70. innerIndent := indent + indentation
  71. for i, item := range array {
  72. result += innerIndent + "\"" + item + "\""
  73. if i < len(array)-1 {
  74. result += ","
  75. }
  76. result += "\n"
  77. }
  78. result += indent + "]"
  79. return result
  80. }
  81. // Render renders a yaml.Node as JSON
  82. func Render(node *yaml.Node) string {
  83. if node.Kind == yaml.DocumentNode {
  84. if len(node.Content) == 1 {
  85. return Render(node.Content[0])
  86. }
  87. } else if node.Kind == yaml.MappingNode {
  88. return renderMappingNode(node, "") + "\n"
  89. } else if node.Kind == yaml.SequenceNode {
  90. return renderSequenceNode(node, "") + "\n"
  91. }
  92. return ""
  93. }
  94. func (object *SchemaNumber) nodeValue() *yaml.Node {
  95. if object.Integer != nil {
  96. return nodeForInt64(*object.Integer)
  97. } else if object.Float != nil {
  98. return nodeForFloat64(*object.Float)
  99. } else {
  100. return nil
  101. }
  102. }
  103. func (object *SchemaOrBoolean) nodeValue() *yaml.Node {
  104. if object.Schema != nil {
  105. return object.Schema.nodeValue()
  106. } else if object.Boolean != nil {
  107. return nodeForBoolean(*object.Boolean)
  108. } else {
  109. return nil
  110. }
  111. }
  112. func nodeForStringArray(array []string) *yaml.Node {
  113. content := make([]*yaml.Node, 0)
  114. for _, item := range array {
  115. content = append(content, nodeForString(item))
  116. }
  117. return nodeForSequence(content)
  118. }
  119. func nodeForSchemaArray(array []*Schema) *yaml.Node {
  120. content := make([]*yaml.Node, 0)
  121. for _, item := range array {
  122. content = append(content, item.nodeValue())
  123. }
  124. return nodeForSequence(content)
  125. }
  126. func (object *StringOrStringArray) nodeValue() *yaml.Node {
  127. if object.String != nil {
  128. return nodeForString(*object.String)
  129. } else if object.StringArray != nil {
  130. return nodeForStringArray(*(object.StringArray))
  131. } else {
  132. return nil
  133. }
  134. }
  135. func (object *SchemaOrStringArray) nodeValue() *yaml.Node {
  136. if object.Schema != nil {
  137. return object.Schema.nodeValue()
  138. } else if object.StringArray != nil {
  139. return nodeForStringArray(*(object.StringArray))
  140. } else {
  141. return nil
  142. }
  143. }
  144. func (object *SchemaOrSchemaArray) nodeValue() *yaml.Node {
  145. if object.Schema != nil {
  146. return object.Schema.nodeValue()
  147. } else if object.SchemaArray != nil {
  148. return nodeForSchemaArray(*(object.SchemaArray))
  149. } else {
  150. return nil
  151. }
  152. }
  153. func (object *SchemaEnumValue) nodeValue() *yaml.Node {
  154. if object.String != nil {
  155. return nodeForString(*object.String)
  156. } else if object.Bool != nil {
  157. return nodeForBoolean(*object.Bool)
  158. } else {
  159. return nil
  160. }
  161. }
  162. func nodeForNamedSchemaArray(array *[]*NamedSchema) *yaml.Node {
  163. content := make([]*yaml.Node, 0)
  164. for _, pair := range *(array) {
  165. content = appendPair(content, pair.Name, pair.Value.nodeValue())
  166. }
  167. return nodeForMapping(content)
  168. }
  169. func nodeForNamedSchemaOrStringArray(array *[]*NamedSchemaOrStringArray) *yaml.Node {
  170. content := make([]*yaml.Node, 0)
  171. for _, pair := range *(array) {
  172. content = appendPair(content, pair.Name, pair.Value.nodeValue())
  173. }
  174. return nodeForMapping(content)
  175. }
  176. func nodeForSchemaEnumArray(array *[]SchemaEnumValue) *yaml.Node {
  177. content := make([]*yaml.Node, 0)
  178. for _, item := range *array {
  179. content = append(content, item.nodeValue())
  180. }
  181. return nodeForSequence(content)
  182. }
  183. func nodeForMapping(content []*yaml.Node) *yaml.Node {
  184. return &yaml.Node{
  185. Kind: yaml.MappingNode,
  186. Content: content,
  187. }
  188. }
  189. func nodeForSequence(content []*yaml.Node) *yaml.Node {
  190. return &yaml.Node{
  191. Kind: yaml.SequenceNode,
  192. Content: content,
  193. }
  194. }
  195. func nodeForString(value string) *yaml.Node {
  196. return &yaml.Node{
  197. Kind: yaml.ScalarNode,
  198. Tag: "!!str",
  199. Value: value,
  200. }
  201. }
  202. func nodeForBoolean(value bool) *yaml.Node {
  203. return &yaml.Node{
  204. Kind: yaml.ScalarNode,
  205. Tag: "!!bool",
  206. Value: fmt.Sprintf("%t", value),
  207. }
  208. }
  209. func nodeForInt64(value int64) *yaml.Node {
  210. return &yaml.Node{
  211. Kind: yaml.ScalarNode,
  212. Tag: "!!int",
  213. Value: fmt.Sprintf("%d", value),
  214. }
  215. }
  216. func nodeForFloat64(value float64) *yaml.Node {
  217. return &yaml.Node{
  218. Kind: yaml.ScalarNode,
  219. Tag: "!!float",
  220. Value: fmt.Sprintf("%f", value),
  221. }
  222. }
  223. func appendPair(nodes []*yaml.Node, name string, value *yaml.Node) []*yaml.Node {
  224. nodes = append(nodes, nodeForString(name))
  225. nodes = append(nodes, value)
  226. return nodes
  227. }
  228. func (schema *Schema) nodeValue() *yaml.Node {
  229. n := &yaml.Node{Kind: yaml.MappingNode}
  230. content := make([]*yaml.Node, 0)
  231. if schema.Title != nil {
  232. content = appendPair(content, "title", nodeForString(*schema.Title))
  233. }
  234. if schema.ID != nil {
  235. content = appendPair(content, "id", nodeForString(*schema.ID))
  236. }
  237. if schema.Schema != nil {
  238. content = appendPair(content, "$schema", nodeForString(*schema.Schema))
  239. }
  240. if schema.Type != nil {
  241. content = appendPair(content, "type", schema.Type.nodeValue())
  242. }
  243. if schema.Items != nil {
  244. content = appendPair(content, "items", schema.Items.nodeValue())
  245. }
  246. if schema.Description != nil {
  247. content = appendPair(content, "description", nodeForString(*schema.Description))
  248. }
  249. if schema.Required != nil {
  250. content = appendPair(content, "required", nodeForStringArray(*schema.Required))
  251. }
  252. if schema.AdditionalProperties != nil {
  253. content = appendPair(content, "additionalProperties", schema.AdditionalProperties.nodeValue())
  254. }
  255. if schema.PatternProperties != nil {
  256. content = appendPair(content, "patternProperties", nodeForNamedSchemaArray(schema.PatternProperties))
  257. }
  258. if schema.Properties != nil {
  259. content = appendPair(content, "properties", nodeForNamedSchemaArray(schema.Properties))
  260. }
  261. if schema.Dependencies != nil {
  262. content = appendPair(content, "dependencies", nodeForNamedSchemaOrStringArray(schema.Dependencies))
  263. }
  264. if schema.Ref != nil {
  265. content = appendPair(content, "$ref", nodeForString(*schema.Ref))
  266. }
  267. if schema.MultipleOf != nil {
  268. content = appendPair(content, "multipleOf", schema.MultipleOf.nodeValue())
  269. }
  270. if schema.Maximum != nil {
  271. content = appendPair(content, "maximum", schema.Maximum.nodeValue())
  272. }
  273. if schema.ExclusiveMaximum != nil {
  274. content = appendPair(content, "exclusiveMaximum", nodeForBoolean(*schema.ExclusiveMaximum))
  275. }
  276. if schema.Minimum != nil {
  277. content = appendPair(content, "minimum", schema.Minimum.nodeValue())
  278. }
  279. if schema.ExclusiveMinimum != nil {
  280. content = appendPair(content, "exclusiveMinimum", nodeForBoolean(*schema.ExclusiveMinimum))
  281. }
  282. if schema.MaxLength != nil {
  283. content = appendPair(content, "maxLength", nodeForInt64(*schema.MaxLength))
  284. }
  285. if schema.MinLength != nil {
  286. content = appendPair(content, "minLength", nodeForInt64(*schema.MinLength))
  287. }
  288. if schema.Pattern != nil {
  289. content = appendPair(content, "pattern", nodeForString(*schema.Pattern))
  290. }
  291. if schema.AdditionalItems != nil {
  292. content = appendPair(content, "additionalItems", schema.AdditionalItems.nodeValue())
  293. }
  294. if schema.MaxItems != nil {
  295. content = appendPair(content, "maxItems", nodeForInt64(*schema.MaxItems))
  296. }
  297. if schema.MinItems != nil {
  298. content = appendPair(content, "minItems", nodeForInt64(*schema.MinItems))
  299. }
  300. if schema.UniqueItems != nil {
  301. content = appendPair(content, "uniqueItems", nodeForBoolean(*schema.UniqueItems))
  302. }
  303. if schema.MaxProperties != nil {
  304. content = appendPair(content, "maxProperties", nodeForInt64(*schema.MaxProperties))
  305. }
  306. if schema.MinProperties != nil {
  307. content = appendPair(content, "minProperties", nodeForInt64(*schema.MinProperties))
  308. }
  309. if schema.Enumeration != nil {
  310. content = appendPair(content, "enum", nodeForSchemaEnumArray(schema.Enumeration))
  311. }
  312. if schema.AllOf != nil {
  313. content = appendPair(content, "allOf", nodeForSchemaArray(*schema.AllOf))
  314. }
  315. if schema.AnyOf != nil {
  316. content = appendPair(content, "anyOf", nodeForSchemaArray(*schema.AnyOf))
  317. }
  318. if schema.OneOf != nil {
  319. content = appendPair(content, "oneOf", nodeForSchemaArray(*schema.OneOf))
  320. }
  321. if schema.Not != nil {
  322. content = appendPair(content, "not", schema.Not.nodeValue())
  323. }
  324. if schema.Definitions != nil {
  325. content = appendPair(content, "definitions", nodeForNamedSchemaArray(schema.Definitions))
  326. }
  327. if schema.Default != nil {
  328. // m = append(m, yaml.MapItem{Key: "default", Value: *schema.Default})
  329. }
  330. if schema.Format != nil {
  331. content = appendPair(content, "format", nodeForString(*schema.Format))
  332. }
  333. n.Content = content
  334. return n
  335. }
  336. // JSONString returns a json representation of a schema.
  337. func (schema *Schema) JSONString() string {
  338. node := schema.nodeValue()
  339. return Render(node)
  340. }