...

Source file src/github.com/qri-io/jsonschema/keywords_object.go

Documentation: github.com/qri-io/jsonschema

     1  package jsonschema
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"regexp"
     8  	"strconv"
     9  
    10  	jptr "github.com/qri-io/jsonpointer"
    11  )
    12  
    13  // Properties defines the properties JSON Schema keyword
    14  type Properties map[string]*Schema
    15  
    16  // NewProperties allocates a new Properties keyword
    17  func NewProperties() Keyword {
    18  	return &Properties{}
    19  }
    20  
    21  // Register implements the Keyword interface for Properties
    22  func (p *Properties) Register(uri string, registry *SchemaRegistry) {
    23  	for _, v := range *p {
    24  		v.Register(uri, registry)
    25  	}
    26  }
    27  
    28  // Resolve implements the Keyword interface for Properties
    29  func (p *Properties) Resolve(pointer jptr.Pointer, uri string) *Schema {
    30  	if pointer == nil {
    31  		return nil
    32  	}
    33  	current := pointer.Head()
    34  	if current == nil {
    35  		return nil
    36  	}
    37  
    38  	if schema, ok := (*p)[*current]; ok {
    39  		return schema.Resolve(pointer.Tail(), uri)
    40  	}
    41  
    42  	return nil
    43  }
    44  
    45  // ValidateKeyword implements the Keyword interface for Properties
    46  func (p Properties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
    47  	schemaDebug("[Properties] Validating")
    48  	if obj, ok := data.(map[string]interface{}); ok {
    49  		subState := currentState.NewSubState()
    50  		for key := range p {
    51  			if _, ok := obj[key]; ok {
    52  				currentState.SetEvaluatedKey(key)
    53  				subState.ClearState()
    54  				subState.DescendBaseFromState(currentState, "properties", key)
    55  				subState.DescendRelativeFromState(currentState, "properties", key)
    56  				subState.DescendInstanceFromState(currentState, key)
    57  
    58  				subState.Errs = &[]KeyError{}
    59  				p[key].ValidateKeyword(ctx, subState, obj[key])
    60  				currentState.AddSubErrors(*subState.Errs...)
    61  				if subState.IsValid() {
    62  					currentState.UpdateEvaluatedPropsAndItems(subState)
    63  				}
    64  			}
    65  		}
    66  	}
    67  }
    68  
    69  // JSONProp implements the JSONPather for Properties
    70  func (p Properties) JSONProp(name string) interface{} {
    71  	return p[name]
    72  }
    73  
    74  // JSONChildren implements the JSONContainer interface for Properties
    75  func (p Properties) JSONChildren() (res map[string]JSONPather) {
    76  	res = map[string]JSONPather{}
    77  	for key, sch := range p {
    78  		res[key] = sch
    79  	}
    80  	return
    81  }
    82  
    83  // Required defines the required JSON Schema keyword
    84  type Required []string
    85  
    86  // NewRequired allocates a new Required keyword
    87  func NewRequired() Keyword {
    88  	return &Required{}
    89  }
    90  
    91  // Register implements the Keyword interface for Required
    92  func (r *Required) Register(uri string, registry *SchemaRegistry) {}
    93  
    94  // Resolve implements the Keyword interface for Required
    95  func (r *Required) Resolve(pointer jptr.Pointer, uri string) *Schema {
    96  	return nil
    97  }
    98  
    99  // ValidateKeyword implements the Keyword interface for Required
   100  func (r Required) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   101  	schemaDebug("[Required] Validating")
   102  	if obj, ok := data.(map[string]interface{}); ok {
   103  		for _, key := range r {
   104  			if _, ok := obj[key]; !ok {
   105  				currentState.AddError(data, fmt.Sprintf(`"%s" value is required`, key))
   106  			}
   107  		}
   108  	}
   109  }
   110  
   111  // JSONProp implements the JSONPather for Required
   112  func (r Required) JSONProp(name string) interface{} {
   113  	idx, err := strconv.Atoi(name)
   114  	if err != nil {
   115  		return nil
   116  	}
   117  	if idx > len(r) || idx < 0 {
   118  		return nil
   119  	}
   120  	return r[idx]
   121  }
   122  
   123  // MaxProperties defines the maxProperties JSON Schema keyword
   124  type MaxProperties int
   125  
   126  // NewMaxProperties allocates a new MaxProperties keyword
   127  func NewMaxProperties() Keyword {
   128  	return new(MaxProperties)
   129  }
   130  
   131  // Register implements the Keyword interface for MaxProperties
   132  func (m *MaxProperties) Register(uri string, registry *SchemaRegistry) {}
   133  
   134  // Resolve implements the Keyword interface for MaxProperties
   135  func (m *MaxProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
   136  	return nil
   137  }
   138  
   139  // ValidateKeyword implements the Keyword interface for MaxProperties
   140  func (m MaxProperties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   141  	schemaDebug("[MaxProperties] Validating")
   142  	if obj, ok := data.(map[string]interface{}); ok {
   143  		if len(obj) > int(m) {
   144  			currentState.AddError(data, fmt.Sprintf("%d object Properties exceed %d maximum", len(obj), m))
   145  		}
   146  	}
   147  }
   148  
   149  // MinProperties defines the minProperties JSON Schema keyword
   150  type MinProperties int
   151  
   152  // NewMinProperties allocates a new MinProperties keyword
   153  func NewMinProperties() Keyword {
   154  	return new(MinProperties)
   155  }
   156  
   157  // Register implements the Keyword interface for MinProperties
   158  func (m *MinProperties) Register(uri string, registry *SchemaRegistry) {}
   159  
   160  // Resolve implements the Keyword interface for MinProperties
   161  func (m *MinProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
   162  	return nil
   163  }
   164  
   165  // ValidateKeyword implements the Keyword interface for MinProperties
   166  func (m MinProperties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   167  	schemaDebug("[MinProperties] Validating")
   168  	if obj, ok := data.(map[string]interface{}); ok {
   169  		if len(obj) < int(m) {
   170  			currentState.AddError(data, fmt.Sprintf("%d object Properties below %d minimum", len(obj), m))
   171  		}
   172  	}
   173  }
   174  
   175  // PatternProperties defines the patternProperties JSON Schema keyword
   176  type PatternProperties []patternSchema
   177  
   178  // NewPatternProperties allocates a new PatternProperties keyword
   179  func NewPatternProperties() Keyword {
   180  	return &PatternProperties{}
   181  }
   182  
   183  type patternSchema struct {
   184  	key    string
   185  	re     *regexp.Regexp
   186  	schema *Schema
   187  }
   188  
   189  // Register implements the Keyword interface for PatternProperties
   190  func (p *PatternProperties) Register(uri string, registry *SchemaRegistry) {
   191  	for _, v := range *p {
   192  		v.schema.Register(uri, registry)
   193  	}
   194  }
   195  
   196  // Resolve implements the Keyword interface for PatternProperties
   197  func (p *PatternProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
   198  	if pointer == nil {
   199  		return nil
   200  	}
   201  	current := pointer.Head()
   202  	if current == nil {
   203  		return nil
   204  	}
   205  
   206  	patProp := &patternSchema{}
   207  
   208  	for _, v := range *p {
   209  		if v.key == *current {
   210  			patProp = &v
   211  			break
   212  		}
   213  	}
   214  
   215  	return patProp.schema.Resolve(pointer.Tail(), uri)
   216  }
   217  
   218  // ValidateKeyword implements the Keyword interface for PatternProperties
   219  func (p PatternProperties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   220  	schemaDebug("[PatternProperties] Validating")
   221  	if obj, ok := data.(map[string]interface{}); ok {
   222  		for key, val := range obj {
   223  			for _, ptn := range p {
   224  				if ptn.re.Match([]byte(key)) {
   225  					currentState.SetEvaluatedKey(key)
   226  					subState := currentState.NewSubState()
   227  					subState.DescendBase("patternProperties", key)
   228  					subState.DescendRelative("patternProperties", key)
   229  					subState.DescendInstance(key)
   230  
   231  					subState.Errs = &[]KeyError{}
   232  					ptn.schema.ValidateKeyword(ctx, subState, val)
   233  					currentState.AddSubErrors(*subState.Errs...)
   234  
   235  					if subState.IsValid() {
   236  						currentState.UpdateEvaluatedPropsAndItems(subState)
   237  					}
   238  				}
   239  			}
   240  		}
   241  	}
   242  }
   243  
   244  // JSONProp implements the JSONPather for PatternProperties
   245  func (p PatternProperties) JSONProp(name string) interface{} {
   246  	for _, pp := range p {
   247  		if pp.key == name {
   248  			return pp.schema
   249  		}
   250  	}
   251  	return nil
   252  }
   253  
   254  // JSONChildren implements the JSONContainer interface for PatternProperties
   255  func (p PatternProperties) JSONChildren() (res map[string]JSONPather) {
   256  	res = map[string]JSONPather{}
   257  	for i, pp := range p {
   258  		res[strconv.Itoa(i)] = pp.schema
   259  	}
   260  	return
   261  }
   262  
   263  // UnmarshalJSON implements the json.Unmarshaler interface for PatternProperties
   264  func (p *PatternProperties) UnmarshalJSON(data []byte) error {
   265  	var props map[string]*Schema
   266  	if err := json.Unmarshal(data, &props); err != nil {
   267  		return err
   268  	}
   269  
   270  	ptn := make(PatternProperties, len(props))
   271  	i := 0
   272  	for key, sch := range props {
   273  		re, err := regexp.Compile(key)
   274  		if err != nil {
   275  			return fmt.Errorf("invalid pattern: %s: %s", key, err.Error())
   276  		}
   277  		ptn[i] = patternSchema{
   278  			key:    key,
   279  			re:     re,
   280  			schema: sch,
   281  		}
   282  		i++
   283  	}
   284  
   285  	*p = ptn
   286  	return nil
   287  }
   288  
   289  // MarshalJSON implements the json.Marshaler interface for PatternProperties
   290  func (p PatternProperties) MarshalJSON() ([]byte, error) {
   291  	obj := map[string]interface{}{}
   292  	for _, prop := range p {
   293  		obj[prop.key] = prop.schema
   294  	}
   295  	return json.Marshal(obj)
   296  }
   297  
   298  // AdditionalProperties defines the additionalProperties JSON Schema keyword
   299  type AdditionalProperties Schema
   300  
   301  // NewAdditionalProperties allocates a new AdditionalProperties keyword
   302  func NewAdditionalProperties() Keyword {
   303  	return &AdditionalProperties{}
   304  }
   305  
   306  // Register implements the Keyword interface for AdditionalProperties
   307  func (ap *AdditionalProperties) Register(uri string, registry *SchemaRegistry) {
   308  	(*Schema)(ap).Register(uri, registry)
   309  }
   310  
   311  // Resolve implements the Keyword interface for AdditionalProperties
   312  func (ap *AdditionalProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
   313  	return (*Schema)(ap).Resolve(pointer, uri)
   314  }
   315  
   316  // ValidateKeyword implements the Keyword interface for AdditionalProperties
   317  func (ap *AdditionalProperties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   318  	schemaDebug("[AdditionalProperties] Validating")
   319  	if obj, ok := data.(map[string]interface{}); ok {
   320  		subState := currentState.NewSubState()
   321  		subState.ClearState()
   322  		subState.DescendBase("additionalProperties")
   323  		subState.DescendRelative("additionalProperties")
   324  		for key := range obj {
   325  			if currentState.IsLocallyEvaluatedKey(key) {
   326  				continue
   327  			}
   328  			if ap.schemaType == schemaTypeFalse {
   329  				currentState.AddError(data, "additional properties are not allowed")
   330  				return
   331  			}
   332  			currentState.SetEvaluatedKey(key)
   333  			subState.ClearState()
   334  			subState.DescendInstanceFromState(currentState, key)
   335  
   336  			(*Schema)(ap).ValidateKeyword(ctx, subState, obj[key])
   337  			currentState.UpdateEvaluatedPropsAndItems(subState)
   338  		}
   339  	}
   340  }
   341  
   342  // UnmarshalJSON implements the json.Unmarshaler interface for AdditionalProperties
   343  func (ap *AdditionalProperties) UnmarshalJSON(data []byte) error {
   344  	sch := &Schema{}
   345  	if err := json.Unmarshal(data, sch); err != nil {
   346  		return err
   347  	}
   348  	*ap = (AdditionalProperties)(*sch)
   349  	return nil
   350  }
   351  
   352  // PropertyNames defines the propertyNames JSON Schema keyword
   353  type PropertyNames Schema
   354  
   355  // NewPropertyNames allocates a new PropertyNames keyword
   356  func NewPropertyNames() Keyword {
   357  	return &PropertyNames{}
   358  }
   359  
   360  // Register implements the Keyword interface for PropertyNames
   361  func (p *PropertyNames) Register(uri string, registry *SchemaRegistry) {
   362  	(*Schema)(p).Register(uri, registry)
   363  }
   364  
   365  // Resolve implements the Keyword interface for PropertyNames
   366  func (p *PropertyNames) Resolve(pointer jptr.Pointer, uri string) *Schema {
   367  	return (*Schema)(p).Resolve(pointer, uri)
   368  }
   369  
   370  // ValidateKeyword implements the Keyword interface for PropertyNames
   371  func (p *PropertyNames) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   372  	schemaDebug("[PropertyNames] Validating")
   373  	if obj, ok := data.(map[string]interface{}); ok {
   374  		for key := range obj {
   375  			subState := currentState.NewSubState()
   376  			subState.DescendBase("propertyNames")
   377  			subState.DescendRelative("propertyNames")
   378  			subState.DescendInstance(key)
   379  			(*Schema)(p).ValidateKeyword(ctx, subState, key)
   380  		}
   381  	}
   382  }
   383  
   384  // JSONProp implements the JSONPather for PropertyNames
   385  func (p PropertyNames) JSONProp(name string) interface{} {
   386  	return Schema(p).JSONProp(name)
   387  }
   388  
   389  // JSONChildren implements the JSONContainer interface for PropertyNames
   390  func (p PropertyNames) JSONChildren() (res map[string]JSONPather) {
   391  	return Schema(p).JSONChildren()
   392  }
   393  
   394  // UnmarshalJSON implements the json.Unmarshaler interface for PropertyNames
   395  func (p *PropertyNames) UnmarshalJSON(data []byte) error {
   396  	var sch Schema
   397  	if err := json.Unmarshal(data, &sch); err != nil {
   398  		return err
   399  	}
   400  	*p = PropertyNames(sch)
   401  	return nil
   402  }
   403  
   404  // MarshalJSON implements the json.Marshaler interface for PropertyNames
   405  func (p PropertyNames) MarshalJSON() ([]byte, error) {
   406  	return json.Marshal(Schema(p))
   407  }
   408  
   409  // DependentSchemas defines the dependentSchemas JSON Schema keyword
   410  type DependentSchemas map[string]SchemaDependency
   411  
   412  // NewDependentSchemas allocates a new DependentSchemas keyword
   413  func NewDependentSchemas() Keyword {
   414  	return &DependentSchemas{}
   415  }
   416  
   417  // Register implements the Keyword interface for DependentSchemas
   418  func (d *DependentSchemas) Register(uri string, registry *SchemaRegistry) {
   419  	for _, v := range *d {
   420  		v.schema.Register(uri, registry)
   421  	}
   422  }
   423  
   424  // Resolve implements the Keyword interface for DependentSchemas
   425  func (d *DependentSchemas) Resolve(pointer jptr.Pointer, uri string) *Schema {
   426  	if pointer == nil {
   427  		return nil
   428  	}
   429  	current := pointer.Head()
   430  	if current == nil {
   431  		return nil
   432  	}
   433  
   434  	if schema, ok := (*d)[*current]; ok {
   435  		return schema.Resolve(pointer.Tail(), uri)
   436  	}
   437  
   438  	return nil
   439  }
   440  
   441  // ValidateKeyword implements the Keyword interface for DependentSchemas
   442  func (d *DependentSchemas) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   443  	schemaDebug("[DependentSchemas] Validating")
   444  	for _, v := range *d {
   445  		subState := currentState.NewSubState()
   446  		subState.DescendBase("dependentSchemas")
   447  		subState.DescendRelative("dependentSchemas")
   448  		subState.Misc["dependencyParent"] = "dependentSchemas"
   449  		v.ValidateKeyword(ctx, subState, data)
   450  	}
   451  }
   452  
   453  type _dependentSchemas map[string]Schema
   454  
   455  // UnmarshalJSON implements the json.Unmarshaler interface for DependentSchemas
   456  func (d *DependentSchemas) UnmarshalJSON(data []byte) error {
   457  	_d := _dependentSchemas{}
   458  	if err := json.Unmarshal(data, &_d); err != nil {
   459  		return err
   460  	}
   461  	ds := DependentSchemas{}
   462  	for k, v := range _d {
   463  		sch := Schema(v)
   464  		ds[k] = SchemaDependency{
   465  			schema: &sch,
   466  			prop:   k,
   467  		}
   468  	}
   469  	*d = ds
   470  	return nil
   471  }
   472  
   473  // JSONProp implements the JSONPather for DependentSchemas
   474  func (d DependentSchemas) JSONProp(name string) interface{} {
   475  	return d[name]
   476  }
   477  
   478  // JSONChildren implements the JSONContainer interface for DependentSchemas
   479  func (d DependentSchemas) JSONChildren() (r map[string]JSONPather) {
   480  	r = map[string]JSONPather{}
   481  	for key, val := range d {
   482  		r[key] = val
   483  	}
   484  	return
   485  }
   486  
   487  // SchemaDependency is the internal representation of a dependent schema
   488  type SchemaDependency struct {
   489  	schema *Schema
   490  	prop   string
   491  }
   492  
   493  // Register implements the Keyword interface for SchemaDependency
   494  func (d *SchemaDependency) Register(uri string, registry *SchemaRegistry) {
   495  	d.schema.Register(uri, registry)
   496  }
   497  
   498  // Resolve implements the Keyword interface for SchemaDependency
   499  func (d *SchemaDependency) Resolve(pointer jptr.Pointer, uri string) *Schema {
   500  	return d.schema.Resolve(pointer, uri)
   501  }
   502  
   503  // ValidateKeyword implements the Keyword interface for SchemaDependency
   504  func (d *SchemaDependency) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   505  	schemaDebug("[SchemaDependency] Validating")
   506  	depsData := map[string]interface{}{}
   507  	ok := false
   508  	if depsData, ok = data.(map[string]interface{}); !ok {
   509  		return
   510  	}
   511  	if _, okProp := depsData[d.prop]; !okProp {
   512  		return
   513  	}
   514  	subState := currentState.NewSubState()
   515  	subState.DescendBase(d.prop)
   516  	subState.DescendRelative(d.prop)
   517  	d.schema.ValidateKeyword(ctx, subState, data)
   518  }
   519  
   520  // MarshalJSON implements the json.Marshaler interface for SchemaDependency
   521  func (d SchemaDependency) MarshalJSON() ([]byte, error) {
   522  	return json.Marshal(d.schema)
   523  }
   524  
   525  // JSONProp implements the JSONPather for SchemaDependency
   526  func (d SchemaDependency) JSONProp(name string) interface{} {
   527  	return d.schema.JSONProp(name)
   528  }
   529  
   530  // DependentRequired defines the dependentRequired JSON Schema keyword
   531  type DependentRequired map[string]PropertyDependency
   532  
   533  // NewDependentRequired allocates a new DependentRequired keyword
   534  func NewDependentRequired() Keyword {
   535  	return &DependentRequired{}
   536  }
   537  
   538  // Register implements the Keyword interface for DependentRequired
   539  func (d *DependentRequired) Register(uri string, registry *SchemaRegistry) {}
   540  
   541  // Resolve implements the Keyword interface for DependentRequired
   542  func (d *DependentRequired) Resolve(pointer jptr.Pointer, uri string) *Schema {
   543  	return nil
   544  }
   545  
   546  // ValidateKeyword implements the Keyword interface for DependentRequired
   547  func (d *DependentRequired) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   548  	schemaDebug("[DependentRequired] Validating")
   549  	for _, prop := range *d {
   550  		subState := currentState.NewSubState()
   551  		subState.DescendBase("dependentRequired")
   552  		subState.DescendRelative("dependentRequired")
   553  		subState.Misc["dependencyParent"] = "dependentRequired"
   554  		prop.ValidateKeyword(ctx, subState, data)
   555  	}
   556  }
   557  
   558  type _dependentRequired map[string][]string
   559  
   560  // UnmarshalJSON implements the json.Unmarshaler interface for DependentRequired
   561  func (d *DependentRequired) UnmarshalJSON(data []byte) error {
   562  	_d := _dependentRequired{}
   563  	if err := json.Unmarshal(data, &_d); err != nil {
   564  		return err
   565  	}
   566  	dr := DependentRequired{}
   567  	for k, v := range _d {
   568  		dr[k] = PropertyDependency{
   569  			dependencies: v,
   570  			prop:         k,
   571  		}
   572  	}
   573  	*d = dr
   574  	return nil
   575  }
   576  
   577  // MarshalJSON implements the json.Marshaler interface for DependentRequired
   578  func (d DependentRequired) MarshalJSON() ([]byte, error) {
   579  	obj := map[string]interface{}{}
   580  	for key, prop := range d {
   581  		obj[key] = prop.dependencies
   582  	}
   583  	return json.Marshal(obj)
   584  }
   585  
   586  // JSONProp implements the JSONPather for DependentRequired
   587  func (d DependentRequired) JSONProp(name string) interface{} {
   588  	return d[name]
   589  }
   590  
   591  // JSONChildren implements the JSONContainer interface for DependentRequired
   592  func (d DependentRequired) JSONChildren() (r map[string]JSONPather) {
   593  	r = map[string]JSONPather{}
   594  	for key, val := range d {
   595  		r[key] = val
   596  	}
   597  	return
   598  }
   599  
   600  // PropertyDependency is the internal representation of a dependent property
   601  type PropertyDependency struct {
   602  	dependencies []string
   603  	prop         string
   604  }
   605  
   606  // Register implements the Keyword interface for PropertyDependency
   607  func (p *PropertyDependency) Register(uri string, registry *SchemaRegistry) {}
   608  
   609  // Resolve implements the Keyword interface for PropertyDependency
   610  func (p *PropertyDependency) Resolve(pointer jptr.Pointer, uri string) *Schema {
   611  	return nil
   612  }
   613  
   614  // ValidateKeyword implements the Keyword interface for PropertyDependency
   615  func (p *PropertyDependency) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   616  	schemaDebug("[PropertyDependency] Validating")
   617  	if obj, ok := data.(map[string]interface{}); ok {
   618  		if obj[p.prop] == nil {
   619  			return
   620  		}
   621  		for _, dep := range p.dependencies {
   622  			if obj[dep] == nil {
   623  				currentState.AddError(data, fmt.Sprintf(`"%s" property is required`, dep))
   624  			}
   625  		}
   626  	}
   627  }
   628  
   629  // JSONProp implements the JSONPather for PropertyDependency
   630  func (p PropertyDependency) JSONProp(name string) interface{} {
   631  	idx, err := strconv.Atoi(name)
   632  	if err != nil {
   633  		return nil
   634  	}
   635  	if idx > len(p.dependencies) || idx < 0 {
   636  		return nil
   637  	}
   638  	return p.dependencies[idx]
   639  }
   640  
   641  // UnevaluatedProperties defines the unevaluatedProperties JSON Schema keyword
   642  type UnevaluatedProperties Schema
   643  
   644  // NewUnevaluatedProperties allocates a new UnevaluatedProperties keyword
   645  func NewUnevaluatedProperties() Keyword {
   646  	return &UnevaluatedProperties{}
   647  }
   648  
   649  // Register implements the Keyword interface for UnevaluatedProperties
   650  func (up *UnevaluatedProperties) Register(uri string, registry *SchemaRegistry) {
   651  	(*Schema)(up).Register(uri, registry)
   652  }
   653  
   654  // Resolve implements the Keyword interface for UnevaluatedProperties
   655  func (up *UnevaluatedProperties) Resolve(pointer jptr.Pointer, uri string) *Schema {
   656  	return (*Schema)(up).Resolve(pointer, uri)
   657  }
   658  
   659  // ValidateKeyword implements the Keyword interface for UnevaluatedProperties
   660  func (up *UnevaluatedProperties) ValidateKeyword(ctx context.Context, currentState *ValidationState, data interface{}) {
   661  	schemaDebug("[UnevaluatedProperties] Validating")
   662  	if obj, ok := data.(map[string]interface{}); ok {
   663  		subState := currentState.NewSubState()
   664  		subState.ClearState()
   665  		subState.DescendBase("unevaluatedProperties")
   666  		subState.DescendRelative("unevaluatedProperties")
   667  		for key := range obj {
   668  			if currentState.IsEvaluatedKey(key) {
   669  				continue
   670  			}
   671  			if up.schemaType == schemaTypeFalse {
   672  				currentState.AddError(data, "unevaluated properties are not allowed")
   673  				return
   674  			}
   675  			subState.DescendInstanceFromState(currentState, key)
   676  
   677  			(*Schema)(up).ValidateKeyword(ctx, subState, obj[key])
   678  		}
   679  	}
   680  }
   681  
   682  // UnmarshalJSON implements the json.Unmarshaler interface for UnevaluatedProperties
   683  func (up *UnevaluatedProperties) UnmarshalJSON(data []byte) error {
   684  	sch := &Schema{}
   685  	if err := json.Unmarshal(data, sch); err != nil {
   686  		return err
   687  	}
   688  	*up = (UnevaluatedProperties)(*sch)
   689  	return nil
   690  }
   691  

View as plain text