...

Source file src/github.com/go-openapi/spec/schema.go

Documentation: github.com/go-openapi/spec

     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  
    15  package spec
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/go-openapi/jsonpointer"
    23  	"github.com/go-openapi/swag"
    24  )
    25  
    26  // BooleanProperty creates a boolean property
    27  func BooleanProperty() *Schema {
    28  	return &Schema{SchemaProps: SchemaProps{Type: []string{"boolean"}}}
    29  }
    30  
    31  // BoolProperty creates a boolean property
    32  func BoolProperty() *Schema { return BooleanProperty() }
    33  
    34  // StringProperty creates a string property
    35  func StringProperty() *Schema {
    36  	return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
    37  }
    38  
    39  // CharProperty creates a string property
    40  func CharProperty() *Schema {
    41  	return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}
    42  }
    43  
    44  // Float64Property creates a float64/double property
    45  func Float64Property() *Schema {
    46  	return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "double"}}
    47  }
    48  
    49  // Float32Property creates a float32/float property
    50  func Float32Property() *Schema {
    51  	return &Schema{SchemaProps: SchemaProps{Type: []string{"number"}, Format: "float"}}
    52  }
    53  
    54  // Int8Property creates an int8 property
    55  func Int8Property() *Schema {
    56  	return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int8"}}
    57  }
    58  
    59  // Int16Property creates an int16 property
    60  func Int16Property() *Schema {
    61  	return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int16"}}
    62  }
    63  
    64  // Int32Property creates an int32 property
    65  func Int32Property() *Schema {
    66  	return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int32"}}
    67  }
    68  
    69  // Int64Property creates an int64 property
    70  func Int64Property() *Schema {
    71  	return &Schema{SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}}
    72  }
    73  
    74  // StrFmtProperty creates a property for the named string format
    75  func StrFmtProperty(format string) *Schema {
    76  	return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: format}}
    77  }
    78  
    79  // DateProperty creates a date property
    80  func DateProperty() *Schema {
    81  	return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date"}}
    82  }
    83  
    84  // DateTimeProperty creates a date time property
    85  func DateTimeProperty() *Schema {
    86  	return &Schema{SchemaProps: SchemaProps{Type: []string{"string"}, Format: "date-time"}}
    87  }
    88  
    89  // MapProperty creates a map property
    90  func MapProperty(property *Schema) *Schema {
    91  	return &Schema{SchemaProps: SchemaProps{Type: []string{"object"},
    92  		AdditionalProperties: &SchemaOrBool{Allows: true, Schema: property}}}
    93  }
    94  
    95  // RefProperty creates a ref property
    96  func RefProperty(name string) *Schema {
    97  	return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
    98  }
    99  
   100  // RefSchema creates a ref property
   101  func RefSchema(name string) *Schema {
   102  	return &Schema{SchemaProps: SchemaProps{Ref: MustCreateRef(name)}}
   103  }
   104  
   105  // ArrayProperty creates an array property
   106  func ArrayProperty(items *Schema) *Schema {
   107  	if items == nil {
   108  		return &Schema{SchemaProps: SchemaProps{Type: []string{"array"}}}
   109  	}
   110  	return &Schema{SchemaProps: SchemaProps{Items: &SchemaOrArray{Schema: items}, Type: []string{"array"}}}
   111  }
   112  
   113  // ComposedSchema creates a schema with allOf
   114  func ComposedSchema(schemas ...Schema) *Schema {
   115  	s := new(Schema)
   116  	s.AllOf = schemas
   117  	return s
   118  }
   119  
   120  // SchemaURL represents a schema url
   121  type SchemaURL string
   122  
   123  // MarshalJSON marshal this to JSON
   124  func (r SchemaURL) MarshalJSON() ([]byte, error) {
   125  	if r == "" {
   126  		return []byte("{}"), nil
   127  	}
   128  	v := map[string]interface{}{"$schema": string(r)}
   129  	return json.Marshal(v)
   130  }
   131  
   132  // UnmarshalJSON unmarshal this from JSON
   133  func (r *SchemaURL) UnmarshalJSON(data []byte) error {
   134  	var v map[string]interface{}
   135  	if err := json.Unmarshal(data, &v); err != nil {
   136  		return err
   137  	}
   138  	return r.fromMap(v)
   139  }
   140  
   141  func (r *SchemaURL) fromMap(v map[string]interface{}) error {
   142  	if v == nil {
   143  		return nil
   144  	}
   145  	if vv, ok := v["$schema"]; ok {
   146  		if str, ok := vv.(string); ok {
   147  			u, err := parseURL(str)
   148  			if err != nil {
   149  				return err
   150  			}
   151  
   152  			*r = SchemaURL(u.String())
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  // SchemaProps describes a JSON schema (draft 4)
   159  type SchemaProps struct {
   160  	ID                   string           `json:"id,omitempty"`
   161  	Ref                  Ref              `json:"-"`
   162  	Schema               SchemaURL        `json:"-"`
   163  	Description          string           `json:"description,omitempty"`
   164  	Type                 StringOrArray    `json:"type,omitempty"`
   165  	Nullable             bool             `json:"nullable,omitempty"`
   166  	Format               string           `json:"format,omitempty"`
   167  	Title                string           `json:"title,omitempty"`
   168  	Default              interface{}      `json:"default,omitempty"`
   169  	Maximum              *float64         `json:"maximum,omitempty"`
   170  	ExclusiveMaximum     bool             `json:"exclusiveMaximum,omitempty"`
   171  	Minimum              *float64         `json:"minimum,omitempty"`
   172  	ExclusiveMinimum     bool             `json:"exclusiveMinimum,omitempty"`
   173  	MaxLength            *int64           `json:"maxLength,omitempty"`
   174  	MinLength            *int64           `json:"minLength,omitempty"`
   175  	Pattern              string           `json:"pattern,omitempty"`
   176  	MaxItems             *int64           `json:"maxItems,omitempty"`
   177  	MinItems             *int64           `json:"minItems,omitempty"`
   178  	UniqueItems          bool             `json:"uniqueItems,omitempty"`
   179  	MultipleOf           *float64         `json:"multipleOf,omitempty"`
   180  	Enum                 []interface{}    `json:"enum,omitempty"`
   181  	MaxProperties        *int64           `json:"maxProperties,omitempty"`
   182  	MinProperties        *int64           `json:"minProperties,omitempty"`
   183  	Required             []string         `json:"required,omitempty"`
   184  	Items                *SchemaOrArray   `json:"items,omitempty"`
   185  	AllOf                []Schema         `json:"allOf,omitempty"`
   186  	OneOf                []Schema         `json:"oneOf,omitempty"`
   187  	AnyOf                []Schema         `json:"anyOf,omitempty"`
   188  	Not                  *Schema          `json:"not,omitempty"`
   189  	Properties           SchemaProperties `json:"properties,omitempty"`
   190  	AdditionalProperties *SchemaOrBool    `json:"additionalProperties,omitempty"`
   191  	PatternProperties    SchemaProperties `json:"patternProperties,omitempty"`
   192  	Dependencies         Dependencies     `json:"dependencies,omitempty"`
   193  	AdditionalItems      *SchemaOrBool    `json:"additionalItems,omitempty"`
   194  	Definitions          Definitions      `json:"definitions,omitempty"`
   195  }
   196  
   197  // SwaggerSchemaProps are additional properties supported by swagger schemas, but not JSON-schema (draft 4)
   198  type SwaggerSchemaProps struct {
   199  	Discriminator string                 `json:"discriminator,omitempty"`
   200  	ReadOnly      bool                   `json:"readOnly,omitempty"`
   201  	XML           *XMLObject             `json:"xml,omitempty"`
   202  	ExternalDocs  *ExternalDocumentation `json:"externalDocs,omitempty"`
   203  	Example       interface{}            `json:"example,omitempty"`
   204  }
   205  
   206  // Schema the schema object allows the definition of input and output data types.
   207  // These types can be objects, but also primitives and arrays.
   208  // This object is based on the [JSON Schema Specification Draft 4](http://json-schema.org/)
   209  // and uses a predefined subset of it.
   210  // On top of this subset, there are extensions provided by this specification to allow for more complete documentation.
   211  //
   212  // For more information: http://goo.gl/8us55a#schemaObject
   213  type Schema struct {
   214  	VendorExtensible
   215  	SchemaProps
   216  	SwaggerSchemaProps
   217  	ExtraProps map[string]interface{} `json:"-"`
   218  }
   219  
   220  // JSONLookup implements an interface to customize json pointer lookup
   221  func (s Schema) JSONLookup(token string) (interface{}, error) {
   222  	if ex, ok := s.Extensions[token]; ok {
   223  		return &ex, nil
   224  	}
   225  
   226  	if ex, ok := s.ExtraProps[token]; ok {
   227  		return &ex, nil
   228  	}
   229  
   230  	r, _, err := jsonpointer.GetForToken(s.SchemaProps, token)
   231  	if r != nil || (err != nil && !strings.HasPrefix(err.Error(), "object has no field")) {
   232  		return r, err
   233  	}
   234  	r, _, err = jsonpointer.GetForToken(s.SwaggerSchemaProps, token)
   235  	return r, err
   236  }
   237  
   238  // WithID sets the id for this schema, allows for chaining
   239  func (s *Schema) WithID(id string) *Schema {
   240  	s.ID = id
   241  	return s
   242  }
   243  
   244  // WithTitle sets the title for this schema, allows for chaining
   245  func (s *Schema) WithTitle(title string) *Schema {
   246  	s.Title = title
   247  	return s
   248  }
   249  
   250  // WithDescription sets the description for this schema, allows for chaining
   251  func (s *Schema) WithDescription(description string) *Schema {
   252  	s.Description = description
   253  	return s
   254  }
   255  
   256  // WithProperties sets the properties for this schema
   257  func (s *Schema) WithProperties(schemas map[string]Schema) *Schema {
   258  	s.Properties = schemas
   259  	return s
   260  }
   261  
   262  // SetProperty sets a property on this schema
   263  func (s *Schema) SetProperty(name string, schema Schema) *Schema {
   264  	if s.Properties == nil {
   265  		s.Properties = make(map[string]Schema)
   266  	}
   267  	s.Properties[name] = schema
   268  	return s
   269  }
   270  
   271  // WithAllOf sets the all of property
   272  func (s *Schema) WithAllOf(schemas ...Schema) *Schema {
   273  	s.AllOf = schemas
   274  	return s
   275  }
   276  
   277  // WithMaxProperties sets the max number of properties an object can have
   278  func (s *Schema) WithMaxProperties(max int64) *Schema {
   279  	s.MaxProperties = &max
   280  	return s
   281  }
   282  
   283  // WithMinProperties sets the min number of properties an object must have
   284  func (s *Schema) WithMinProperties(min int64) *Schema {
   285  	s.MinProperties = &min
   286  	return s
   287  }
   288  
   289  // Typed sets the type of this schema for a single value item
   290  func (s *Schema) Typed(tpe, format string) *Schema {
   291  	s.Type = []string{tpe}
   292  	s.Format = format
   293  	return s
   294  }
   295  
   296  // AddType adds a type with potential format to the types for this schema
   297  func (s *Schema) AddType(tpe, format string) *Schema {
   298  	s.Type = append(s.Type, tpe)
   299  	if format != "" {
   300  		s.Format = format
   301  	}
   302  	return s
   303  }
   304  
   305  // AsNullable flags this schema as nullable.
   306  func (s *Schema) AsNullable() *Schema {
   307  	s.Nullable = true
   308  	return s
   309  }
   310  
   311  // CollectionOf a fluent builder method for an array parameter
   312  func (s *Schema) CollectionOf(items Schema) *Schema {
   313  	s.Type = []string{jsonArray}
   314  	s.Items = &SchemaOrArray{Schema: &items}
   315  	return s
   316  }
   317  
   318  // WithDefault sets the default value on this parameter
   319  func (s *Schema) WithDefault(defaultValue interface{}) *Schema {
   320  	s.Default = defaultValue
   321  	return s
   322  }
   323  
   324  // WithRequired flags this parameter as required
   325  func (s *Schema) WithRequired(items ...string) *Schema {
   326  	s.Required = items
   327  	return s
   328  }
   329  
   330  // AddRequired  adds field names to the required properties array
   331  func (s *Schema) AddRequired(items ...string) *Schema {
   332  	s.Required = append(s.Required, items...)
   333  	return s
   334  }
   335  
   336  // WithMaxLength sets a max length value
   337  func (s *Schema) WithMaxLength(max int64) *Schema {
   338  	s.MaxLength = &max
   339  	return s
   340  }
   341  
   342  // WithMinLength sets a min length value
   343  func (s *Schema) WithMinLength(min int64) *Schema {
   344  	s.MinLength = &min
   345  	return s
   346  }
   347  
   348  // WithPattern sets a pattern value
   349  func (s *Schema) WithPattern(pattern string) *Schema {
   350  	s.Pattern = pattern
   351  	return s
   352  }
   353  
   354  // WithMultipleOf sets a multiple of value
   355  func (s *Schema) WithMultipleOf(number float64) *Schema {
   356  	s.MultipleOf = &number
   357  	return s
   358  }
   359  
   360  // WithMaximum sets a maximum number value
   361  func (s *Schema) WithMaximum(max float64, exclusive bool) *Schema {
   362  	s.Maximum = &max
   363  	s.ExclusiveMaximum = exclusive
   364  	return s
   365  }
   366  
   367  // WithMinimum sets a minimum number value
   368  func (s *Schema) WithMinimum(min float64, exclusive bool) *Schema {
   369  	s.Minimum = &min
   370  	s.ExclusiveMinimum = exclusive
   371  	return s
   372  }
   373  
   374  // WithEnum sets a the enum values (replace)
   375  func (s *Schema) WithEnum(values ...interface{}) *Schema {
   376  	s.Enum = append([]interface{}{}, values...)
   377  	return s
   378  }
   379  
   380  // WithMaxItems sets the max items
   381  func (s *Schema) WithMaxItems(size int64) *Schema {
   382  	s.MaxItems = &size
   383  	return s
   384  }
   385  
   386  // WithMinItems sets the min items
   387  func (s *Schema) WithMinItems(size int64) *Schema {
   388  	s.MinItems = &size
   389  	return s
   390  }
   391  
   392  // UniqueValues dictates that this array can only have unique items
   393  func (s *Schema) UniqueValues() *Schema {
   394  	s.UniqueItems = true
   395  	return s
   396  }
   397  
   398  // AllowDuplicates this array can have duplicates
   399  func (s *Schema) AllowDuplicates() *Schema {
   400  	s.UniqueItems = false
   401  	return s
   402  }
   403  
   404  // AddToAllOf adds a schema to the allOf property
   405  func (s *Schema) AddToAllOf(schemas ...Schema) *Schema {
   406  	s.AllOf = append(s.AllOf, schemas...)
   407  	return s
   408  }
   409  
   410  // WithDiscriminator sets the name of the discriminator field
   411  func (s *Schema) WithDiscriminator(discriminator string) *Schema {
   412  	s.Discriminator = discriminator
   413  	return s
   414  }
   415  
   416  // AsReadOnly flags this schema as readonly
   417  func (s *Schema) AsReadOnly() *Schema {
   418  	s.ReadOnly = true
   419  	return s
   420  }
   421  
   422  // AsWritable flags this schema as writeable (not read-only)
   423  func (s *Schema) AsWritable() *Schema {
   424  	s.ReadOnly = false
   425  	return s
   426  }
   427  
   428  // WithExample sets the example for this schema
   429  func (s *Schema) WithExample(example interface{}) *Schema {
   430  	s.Example = example
   431  	return s
   432  }
   433  
   434  // WithExternalDocs sets/removes the external docs for/from this schema.
   435  // When you pass empty strings as params the external documents will be removed.
   436  // When you pass non-empty string as one value then those values will be used on the external docs object.
   437  // So when you pass a non-empty description, you should also pass the url and vice versa.
   438  func (s *Schema) WithExternalDocs(description, url string) *Schema {
   439  	if description == "" && url == "" {
   440  		s.ExternalDocs = nil
   441  		return s
   442  	}
   443  
   444  	if s.ExternalDocs == nil {
   445  		s.ExternalDocs = &ExternalDocumentation{}
   446  	}
   447  	s.ExternalDocs.Description = description
   448  	s.ExternalDocs.URL = url
   449  	return s
   450  }
   451  
   452  // WithXMLName sets the xml name for the object
   453  func (s *Schema) WithXMLName(name string) *Schema {
   454  	if s.XML == nil {
   455  		s.XML = new(XMLObject)
   456  	}
   457  	s.XML.Name = name
   458  	return s
   459  }
   460  
   461  // WithXMLNamespace sets the xml namespace for the object
   462  func (s *Schema) WithXMLNamespace(namespace string) *Schema {
   463  	if s.XML == nil {
   464  		s.XML = new(XMLObject)
   465  	}
   466  	s.XML.Namespace = namespace
   467  	return s
   468  }
   469  
   470  // WithXMLPrefix sets the xml prefix for the object
   471  func (s *Schema) WithXMLPrefix(prefix string) *Schema {
   472  	if s.XML == nil {
   473  		s.XML = new(XMLObject)
   474  	}
   475  	s.XML.Prefix = prefix
   476  	return s
   477  }
   478  
   479  // AsXMLAttribute flags this object as xml attribute
   480  func (s *Schema) AsXMLAttribute() *Schema {
   481  	if s.XML == nil {
   482  		s.XML = new(XMLObject)
   483  	}
   484  	s.XML.Attribute = true
   485  	return s
   486  }
   487  
   488  // AsXMLElement flags this object as an xml node
   489  func (s *Schema) AsXMLElement() *Schema {
   490  	if s.XML == nil {
   491  		s.XML = new(XMLObject)
   492  	}
   493  	s.XML.Attribute = false
   494  	return s
   495  }
   496  
   497  // AsWrappedXML flags this object as wrapped, this is mostly useful for array types
   498  func (s *Schema) AsWrappedXML() *Schema {
   499  	if s.XML == nil {
   500  		s.XML = new(XMLObject)
   501  	}
   502  	s.XML.Wrapped = true
   503  	return s
   504  }
   505  
   506  // AsUnwrappedXML flags this object as an xml node
   507  func (s *Schema) AsUnwrappedXML() *Schema {
   508  	if s.XML == nil {
   509  		s.XML = new(XMLObject)
   510  	}
   511  	s.XML.Wrapped = false
   512  	return s
   513  }
   514  
   515  // SetValidations defines all schema validations.
   516  //
   517  // NOTE: Required, ReadOnly, AllOf, AnyOf, OneOf and Not are not considered.
   518  func (s *Schema) SetValidations(val SchemaValidations) {
   519  	s.Maximum = val.Maximum
   520  	s.ExclusiveMaximum = val.ExclusiveMaximum
   521  	s.Minimum = val.Minimum
   522  	s.ExclusiveMinimum = val.ExclusiveMinimum
   523  	s.MaxLength = val.MaxLength
   524  	s.MinLength = val.MinLength
   525  	s.Pattern = val.Pattern
   526  	s.MaxItems = val.MaxItems
   527  	s.MinItems = val.MinItems
   528  	s.UniqueItems = val.UniqueItems
   529  	s.MultipleOf = val.MultipleOf
   530  	s.Enum = val.Enum
   531  	s.MinProperties = val.MinProperties
   532  	s.MaxProperties = val.MaxProperties
   533  	s.PatternProperties = val.PatternProperties
   534  }
   535  
   536  // WithValidations is a fluent method to set schema validations
   537  func (s *Schema) WithValidations(val SchemaValidations) *Schema {
   538  	s.SetValidations(val)
   539  	return s
   540  }
   541  
   542  // Validations returns a clone of the validations for this schema
   543  func (s Schema) Validations() SchemaValidations {
   544  	return SchemaValidations{
   545  		CommonValidations: CommonValidations{
   546  			Maximum:          s.Maximum,
   547  			ExclusiveMaximum: s.ExclusiveMaximum,
   548  			Minimum:          s.Minimum,
   549  			ExclusiveMinimum: s.ExclusiveMinimum,
   550  			MaxLength:        s.MaxLength,
   551  			MinLength:        s.MinLength,
   552  			Pattern:          s.Pattern,
   553  			MaxItems:         s.MaxItems,
   554  			MinItems:         s.MinItems,
   555  			UniqueItems:      s.UniqueItems,
   556  			MultipleOf:       s.MultipleOf,
   557  			Enum:             s.Enum,
   558  		},
   559  		MinProperties:     s.MinProperties,
   560  		MaxProperties:     s.MaxProperties,
   561  		PatternProperties: s.PatternProperties,
   562  	}
   563  }
   564  
   565  // MarshalJSON marshal this to JSON
   566  func (s Schema) MarshalJSON() ([]byte, error) {
   567  	b1, err := json.Marshal(s.SchemaProps)
   568  	if err != nil {
   569  		return nil, fmt.Errorf("schema props %v", err)
   570  	}
   571  	b2, err := json.Marshal(s.VendorExtensible)
   572  	if err != nil {
   573  		return nil, fmt.Errorf("vendor props %v", err)
   574  	}
   575  	b3, err := s.Ref.MarshalJSON()
   576  	if err != nil {
   577  		return nil, fmt.Errorf("ref prop %v", err)
   578  	}
   579  	b4, err := s.Schema.MarshalJSON()
   580  	if err != nil {
   581  		return nil, fmt.Errorf("schema prop %v", err)
   582  	}
   583  	b5, err := json.Marshal(s.SwaggerSchemaProps)
   584  	if err != nil {
   585  		return nil, fmt.Errorf("common validations %v", err)
   586  	}
   587  	var b6 []byte
   588  	if s.ExtraProps != nil {
   589  		jj, err := json.Marshal(s.ExtraProps)
   590  		if err != nil {
   591  			return nil, fmt.Errorf("extra props %v", err)
   592  		}
   593  		b6 = jj
   594  	}
   595  	return swag.ConcatJSON(b1, b2, b3, b4, b5, b6), nil
   596  }
   597  
   598  // UnmarshalJSON marshal this from JSON
   599  func (s *Schema) UnmarshalJSON(data []byte) error {
   600  	props := struct {
   601  		SchemaProps
   602  		SwaggerSchemaProps
   603  	}{}
   604  	if err := json.Unmarshal(data, &props); err != nil {
   605  		return err
   606  	}
   607  
   608  	sch := Schema{
   609  		SchemaProps:        props.SchemaProps,
   610  		SwaggerSchemaProps: props.SwaggerSchemaProps,
   611  	}
   612  
   613  	var d map[string]interface{}
   614  	if err := json.Unmarshal(data, &d); err != nil {
   615  		return err
   616  	}
   617  
   618  	_ = sch.Ref.fromMap(d)
   619  	_ = sch.Schema.fromMap(d)
   620  
   621  	delete(d, "$ref")
   622  	delete(d, "$schema")
   623  	for _, pn := range swag.DefaultJSONNameProvider.GetJSONNames(s) {
   624  		delete(d, pn)
   625  	}
   626  
   627  	for k, vv := range d {
   628  		lk := strings.ToLower(k)
   629  		if strings.HasPrefix(lk, "x-") {
   630  			if sch.Extensions == nil {
   631  				sch.Extensions = map[string]interface{}{}
   632  			}
   633  			sch.Extensions[k] = vv
   634  			continue
   635  		}
   636  		if sch.ExtraProps == nil {
   637  			sch.ExtraProps = map[string]interface{}{}
   638  		}
   639  		sch.ExtraProps[k] = vv
   640  	}
   641  
   642  	*s = sch
   643  
   644  	return nil
   645  }
   646  

View as plain text