reader.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  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. //go:generate go run generate-base.go
  15. package jsonschema
  16. import (
  17. "fmt"
  18. "io/ioutil"
  19. "strconv"
  20. "gopkg.in/yaml.v3"
  21. )
  22. // This is a global map of all known Schemas.
  23. // It is initialized when the first Schema is created and inserted.
  24. var schemas map[string]*Schema
  25. // NewBaseSchema builds a schema object from an embedded json representation.
  26. func NewBaseSchema() (schema *Schema, err error) {
  27. b, err := baseSchemaBytes()
  28. if err != nil {
  29. return nil, err
  30. }
  31. var node yaml.Node
  32. err = yaml.Unmarshal(b, &node)
  33. if err != nil {
  34. return nil, err
  35. }
  36. return NewSchemaFromObject(&node), nil
  37. }
  38. // NewSchemaFromFile reads a schema from a file.
  39. // Currently this assumes that schemas are stored in the source distribution of this project.
  40. func NewSchemaFromFile(filename string) (schema *Schema, err error) {
  41. file, err := ioutil.ReadFile(filename)
  42. if err != nil {
  43. return nil, err
  44. }
  45. var node yaml.Node
  46. err = yaml.Unmarshal(file, &node)
  47. if err != nil {
  48. return nil, err
  49. }
  50. return NewSchemaFromObject(&node), nil
  51. }
  52. // NewSchemaFromObject constructs a schema from a parsed JSON object.
  53. // Due to the complexity of the schema representation, this is a
  54. // custom reader and not the standard Go JSON reader (encoding/json).
  55. func NewSchemaFromObject(jsonData *yaml.Node) *Schema {
  56. switch jsonData.Kind {
  57. case yaml.DocumentNode:
  58. return NewSchemaFromObject(jsonData.Content[0])
  59. case yaml.MappingNode:
  60. schema := &Schema{}
  61. for i := 0; i < len(jsonData.Content); i += 2 {
  62. k := jsonData.Content[i].Value
  63. v := jsonData.Content[i+1]
  64. switch k {
  65. case "$schema":
  66. schema.Schema = schema.stringValue(v)
  67. case "id":
  68. schema.ID = schema.stringValue(v)
  69. case "multipleOf":
  70. schema.MultipleOf = schema.numberValue(v)
  71. case "maximum":
  72. schema.Maximum = schema.numberValue(v)
  73. case "exclusiveMaximum":
  74. schema.ExclusiveMaximum = schema.boolValue(v)
  75. case "minimum":
  76. schema.Minimum = schema.numberValue(v)
  77. case "exclusiveMinimum":
  78. schema.ExclusiveMinimum = schema.boolValue(v)
  79. case "maxLength":
  80. schema.MaxLength = schema.intValue(v)
  81. case "minLength":
  82. schema.MinLength = schema.intValue(v)
  83. case "pattern":
  84. schema.Pattern = schema.stringValue(v)
  85. case "additionalItems":
  86. schema.AdditionalItems = schema.schemaOrBooleanValue(v)
  87. case "items":
  88. schema.Items = schema.schemaOrSchemaArrayValue(v)
  89. case "maxItems":
  90. schema.MaxItems = schema.intValue(v)
  91. case "minItems":
  92. schema.MinItems = schema.intValue(v)
  93. case "uniqueItems":
  94. schema.UniqueItems = schema.boolValue(v)
  95. case "maxProperties":
  96. schema.MaxProperties = schema.intValue(v)
  97. case "minProperties":
  98. schema.MinProperties = schema.intValue(v)
  99. case "required":
  100. schema.Required = schema.arrayOfStringsValue(v)
  101. case "additionalProperties":
  102. schema.AdditionalProperties = schema.schemaOrBooleanValue(v)
  103. case "properties":
  104. schema.Properties = schema.mapOfSchemasValue(v)
  105. case "patternProperties":
  106. schema.PatternProperties = schema.mapOfSchemasValue(v)
  107. case "dependencies":
  108. schema.Dependencies = schema.mapOfSchemasOrStringArraysValue(v)
  109. case "enum":
  110. schema.Enumeration = schema.arrayOfEnumValuesValue(v)
  111. case "type":
  112. schema.Type = schema.stringOrStringArrayValue(v)
  113. case "allOf":
  114. schema.AllOf = schema.arrayOfSchemasValue(v)
  115. case "anyOf":
  116. schema.AnyOf = schema.arrayOfSchemasValue(v)
  117. case "oneOf":
  118. schema.OneOf = schema.arrayOfSchemasValue(v)
  119. case "not":
  120. schema.Not = NewSchemaFromObject(v)
  121. case "definitions":
  122. schema.Definitions = schema.mapOfSchemasValue(v)
  123. case "title":
  124. schema.Title = schema.stringValue(v)
  125. case "description":
  126. schema.Description = schema.stringValue(v)
  127. case "default":
  128. schema.Default = v
  129. case "format":
  130. schema.Format = schema.stringValue(v)
  131. case "$ref":
  132. schema.Ref = schema.stringValue(v)
  133. default:
  134. fmt.Printf("UNSUPPORTED (%s)\n", k)
  135. }
  136. }
  137. // insert schema in global map
  138. if schema.ID != nil {
  139. if schemas == nil {
  140. schemas = make(map[string]*Schema, 0)
  141. }
  142. schemas[*(schema.ID)] = schema
  143. }
  144. return schema
  145. default:
  146. fmt.Printf("schemaValue: unexpected node %+v\n", jsonData)
  147. return nil
  148. }
  149. return nil
  150. }
  151. //
  152. // BUILDERS
  153. // The following methods build elements of Schemas from interface{} values.
  154. // Each returns nil if it is unable to build the desired element.
  155. //
  156. // Gets the string value of an interface{} value if possible.
  157. func (schema *Schema) stringValue(v *yaml.Node) *string {
  158. switch v.Kind {
  159. case yaml.ScalarNode:
  160. return &v.Value
  161. default:
  162. fmt.Printf("stringValue: unexpected node %+v\n", v)
  163. }
  164. return nil
  165. }
  166. // Gets the numeric value of an interface{} value if possible.
  167. func (schema *Schema) numberValue(v *yaml.Node) *SchemaNumber {
  168. number := &SchemaNumber{}
  169. switch v.Kind {
  170. case yaml.ScalarNode:
  171. switch v.Tag {
  172. case "!!float":
  173. v2, _ := strconv.ParseFloat(v.Value, 64)
  174. number.Float = &v2
  175. return number
  176. case "!!int":
  177. v2, _ := strconv.ParseInt(v.Value, 10, 64)
  178. number.Integer = &v2
  179. return number
  180. default:
  181. fmt.Printf("stringValue: unexpected node %+v\n", v)
  182. }
  183. default:
  184. fmt.Printf("stringValue: unexpected node %+v\n", v)
  185. }
  186. return nil
  187. }
  188. // Gets the integer value of an interface{} value if possible.
  189. func (schema *Schema) intValue(v *yaml.Node) *int64 {
  190. switch v.Kind {
  191. case yaml.ScalarNode:
  192. switch v.Tag {
  193. case "!!float":
  194. v2, _ := strconv.ParseFloat(v.Value, 64)
  195. v3 := int64(v2)
  196. return &v3
  197. case "!!int":
  198. v2, _ := strconv.ParseInt(v.Value, 10, 64)
  199. return &v2
  200. default:
  201. fmt.Printf("intValue: unexpected node %+v\n", v)
  202. }
  203. default:
  204. fmt.Printf("intValue: unexpected node %+v\n", v)
  205. }
  206. return nil
  207. }
  208. // Gets the bool value of an interface{} value if possible.
  209. func (schema *Schema) boolValue(v *yaml.Node) *bool {
  210. switch v.Kind {
  211. case yaml.ScalarNode:
  212. switch v.Tag {
  213. case "!!bool":
  214. v2, _ := strconv.ParseBool(v.Value)
  215. return &v2
  216. default:
  217. fmt.Printf("boolValue: unexpected node %+v\n", v)
  218. }
  219. default:
  220. fmt.Printf("boolValue: unexpected node %+v\n", v)
  221. }
  222. return nil
  223. }
  224. // Gets a map of Schemas from an interface{} value if possible.
  225. func (schema *Schema) mapOfSchemasValue(v *yaml.Node) *[]*NamedSchema {
  226. switch v.Kind {
  227. case yaml.MappingNode:
  228. m := make([]*NamedSchema, 0)
  229. for i := 0; i < len(v.Content); i += 2 {
  230. k2 := v.Content[i].Value
  231. v2 := v.Content[i+1]
  232. pair := &NamedSchema{Name: k2, Value: NewSchemaFromObject(v2)}
  233. m = append(m, pair)
  234. }
  235. return &m
  236. default:
  237. fmt.Printf("mapOfSchemasValue: unexpected node %+v\n", v)
  238. }
  239. return nil
  240. }
  241. // Gets an array of Schemas from an interface{} value if possible.
  242. func (schema *Schema) arrayOfSchemasValue(v *yaml.Node) *[]*Schema {
  243. switch v.Kind {
  244. case yaml.SequenceNode:
  245. m := make([]*Schema, 0)
  246. for _, v2 := range v.Content {
  247. switch v2.Kind {
  248. case yaml.MappingNode:
  249. s := NewSchemaFromObject(v2)
  250. m = append(m, s)
  251. default:
  252. fmt.Printf("arrayOfSchemasValue: unexpected node %+v\n", v2)
  253. }
  254. }
  255. return &m
  256. case yaml.MappingNode:
  257. m := make([]*Schema, 0)
  258. s := NewSchemaFromObject(v)
  259. m = append(m, s)
  260. return &m
  261. default:
  262. fmt.Printf("arrayOfSchemasValue: unexpected node %+v\n", v)
  263. }
  264. return nil
  265. }
  266. // Gets a Schema or an array of Schemas from an interface{} value if possible.
  267. func (schema *Schema) schemaOrSchemaArrayValue(v *yaml.Node) *SchemaOrSchemaArray {
  268. switch v.Kind {
  269. case yaml.SequenceNode:
  270. m := make([]*Schema, 0)
  271. for _, v2 := range v.Content {
  272. switch v2.Kind {
  273. case yaml.MappingNode:
  274. s := NewSchemaFromObject(v2)
  275. m = append(m, s)
  276. default:
  277. fmt.Printf("schemaOrSchemaArrayValue: unexpected node %+v\n", v2)
  278. }
  279. }
  280. return &SchemaOrSchemaArray{SchemaArray: &m}
  281. case yaml.MappingNode:
  282. s := NewSchemaFromObject(v)
  283. return &SchemaOrSchemaArray{Schema: s}
  284. default:
  285. fmt.Printf("schemaOrSchemaArrayValue: unexpected node %+v\n", v)
  286. }
  287. return nil
  288. }
  289. // Gets an array of strings from an interface{} value if possible.
  290. func (schema *Schema) arrayOfStringsValue(v *yaml.Node) *[]string {
  291. switch v.Kind {
  292. case yaml.ScalarNode:
  293. a := []string{v.Value}
  294. return &a
  295. case yaml.SequenceNode:
  296. a := make([]string, 0)
  297. for _, v2 := range v.Content {
  298. switch v2.Kind {
  299. case yaml.ScalarNode:
  300. a = append(a, v2.Value)
  301. default:
  302. fmt.Printf("arrayOfStringsValue: unexpected node %+v\n", v2)
  303. }
  304. }
  305. return &a
  306. default:
  307. fmt.Printf("arrayOfStringsValue: unexpected node %+v\n", v)
  308. }
  309. return nil
  310. }
  311. // Gets a string or an array of strings from an interface{} value if possible.
  312. func (schema *Schema) stringOrStringArrayValue(v *yaml.Node) *StringOrStringArray {
  313. switch v.Kind {
  314. case yaml.ScalarNode:
  315. s := &StringOrStringArray{}
  316. s.String = &v.Value
  317. return s
  318. case yaml.SequenceNode:
  319. a := make([]string, 0)
  320. for _, v2 := range v.Content {
  321. switch v2.Kind {
  322. case yaml.ScalarNode:
  323. a = append(a, v2.Value)
  324. default:
  325. fmt.Printf("arrayOfStringsValue: unexpected node %+v\n", v2)
  326. }
  327. }
  328. s := &StringOrStringArray{}
  329. s.StringArray = &a
  330. return s
  331. default:
  332. fmt.Printf("arrayOfStringsValue: unexpected node %+v\n", v)
  333. }
  334. return nil
  335. }
  336. // Gets an array of enum values from an interface{} value if possible.
  337. func (schema *Schema) arrayOfEnumValuesValue(v *yaml.Node) *[]SchemaEnumValue {
  338. a := make([]SchemaEnumValue, 0)
  339. switch v.Kind {
  340. case yaml.SequenceNode:
  341. for _, v2 := range v.Content {
  342. switch v2.Kind {
  343. case yaml.ScalarNode:
  344. switch v2.Tag {
  345. case "!!str":
  346. a = append(a, SchemaEnumValue{String: &v2.Value})
  347. case "!!bool":
  348. v3, _ := strconv.ParseBool(v2.Value)
  349. a = append(a, SchemaEnumValue{Bool: &v3})
  350. default:
  351. fmt.Printf("arrayOfEnumValuesValue: unexpected type %s\n", v2.Tag)
  352. }
  353. default:
  354. fmt.Printf("arrayOfEnumValuesValue: unexpected node %+v\n", v2)
  355. }
  356. }
  357. default:
  358. fmt.Printf("arrayOfEnumValuesValue: unexpected node %+v\n", v)
  359. }
  360. return &a
  361. }
  362. // Gets a map of schemas or string arrays from an interface{} value if possible.
  363. func (schema *Schema) mapOfSchemasOrStringArraysValue(v *yaml.Node) *[]*NamedSchemaOrStringArray {
  364. m := make([]*NamedSchemaOrStringArray, 0)
  365. switch v.Kind {
  366. case yaml.MappingNode:
  367. for i := 0; i < len(v.Content); i += 2 {
  368. k2 := v.Content[i].Value
  369. v2 := v.Content[i+1]
  370. switch v2.Kind {
  371. case yaml.SequenceNode:
  372. a := make([]string, 0)
  373. for _, v3 := range v2.Content {
  374. switch v3.Kind {
  375. case yaml.ScalarNode:
  376. a = append(a, v3.Value)
  377. default:
  378. fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected node %+v\n", v3)
  379. }
  380. }
  381. s := &SchemaOrStringArray{}
  382. s.StringArray = &a
  383. pair := &NamedSchemaOrStringArray{Name: k2, Value: s}
  384. m = append(m, pair)
  385. default:
  386. fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected node %+v\n", v2)
  387. }
  388. }
  389. default:
  390. fmt.Printf("mapOfSchemasOrStringArraysValue: unexpected node %+v\n", v)
  391. }
  392. return &m
  393. }
  394. // Gets a schema or a boolean value from an interface{} value if possible.
  395. func (schema *Schema) schemaOrBooleanValue(v *yaml.Node) *SchemaOrBoolean {
  396. schemaOrBoolean := &SchemaOrBoolean{}
  397. switch v.Kind {
  398. case yaml.ScalarNode:
  399. v2, _ := strconv.ParseBool(v.Value)
  400. schemaOrBoolean.Boolean = &v2
  401. case yaml.MappingNode:
  402. schemaOrBoolean.Schema = NewSchemaFromObject(v)
  403. default:
  404. fmt.Printf("schemaOrBooleanValue: unexpected node %+v\n", v)
  405. }
  406. return schemaOrBoolean
  407. }