...

Source file src/github.com/google/gnostic-models/jsonschema/reader.go

Documentation: github.com/google/gnostic-models/jsonschema

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

View as plain text