reader.go 11 KB

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