...

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

Documentation: github.com/qri-io/jsonschema

     1  package jsonschema
     2  
     3  import (
     4  	jptr "github.com/qri-io/jsonpointer"
     5  )
     6  
     7  // ValidationState holds the schema validation state
     8  // The aim is to have one global validation state
     9  // and use local sub states when evaluating parallel branches
    10  // TODO(arqu): make sure this is safe for concurrent use
    11  type ValidationState struct {
    12  	Local                *Schema
    13  	Root                 *Schema
    14  	RecursiveAnchor      *Schema
    15  	BaseURI              string
    16  	InstanceLocation     *jptr.Pointer
    17  	RelativeLocation     *jptr.Pointer
    18  	BaseRelativeLocation *jptr.Pointer
    19  
    20  	LocalRegistry *SchemaRegistry
    21  
    22  	EvaluatedPropertyNames      *map[string]bool
    23  	LocalEvaluatedPropertyNames *map[string]bool
    24  	LastEvaluatedIndex          int
    25  	LocalLastEvaluatedIndex     int
    26  	Misc                        map[string]interface{}
    27  
    28  	Errs *[]KeyError
    29  }
    30  
    31  // NewValidationState creates a new ValidationState with the provided location pointers and data instance
    32  func NewValidationState(s *Schema) *ValidationState {
    33  	tmpBRLprt := jptr.NewPointer()
    34  	tmpRLprt := jptr.NewPointer()
    35  	tmpILprt := jptr.NewPointer()
    36  	return &ValidationState{
    37  		Root:                        s,
    38  		BaseRelativeLocation:        &tmpBRLprt,
    39  		RelativeLocation:            &tmpRLprt,
    40  		InstanceLocation:            &tmpILprt,
    41  		LocalRegistry:               &SchemaRegistry{},
    42  		LastEvaluatedIndex:          -1,
    43  		LocalLastEvaluatedIndex:     -1,
    44  		EvaluatedPropertyNames:      &map[string]bool{},
    45  		LocalEvaluatedPropertyNames: &map[string]bool{},
    46  		Misc:                        map[string]interface{}{},
    47  		Errs:                        &[]KeyError{},
    48  	}
    49  }
    50  
    51  // NewSubState creates a new ValidationState from an existing ValidationState
    52  func (vs *ValidationState) NewSubState() *ValidationState {
    53  	return &ValidationState{
    54  		Local:                       vs.Local,
    55  		Root:                        vs.Root,
    56  		RecursiveAnchor:             vs.RecursiveAnchor,
    57  		LastEvaluatedIndex:          vs.LastEvaluatedIndex,
    58  		LocalLastEvaluatedIndex:     vs.LocalLastEvaluatedIndex,
    59  		BaseURI:                     vs.BaseURI,
    60  		InstanceLocation:            vs.InstanceLocation,
    61  		RelativeLocation:            vs.RelativeLocation,
    62  		BaseRelativeLocation:        vs.RelativeLocation,
    63  		LocalRegistry:               vs.LocalRegistry,
    64  		EvaluatedPropertyNames:      vs.EvaluatedPropertyNames,
    65  		LocalEvaluatedPropertyNames: vs.LocalEvaluatedPropertyNames,
    66  		Misc:                        map[string]interface{}{},
    67  		Errs:                        vs.Errs,
    68  	}
    69  }
    70  
    71  // ClearState resets a schema to it's core elements
    72  func (vs *ValidationState) ClearState() {
    73  	vs.EvaluatedPropertyNames = &map[string]bool{}
    74  	vs.LocalEvaluatedPropertyNames = &map[string]bool{}
    75  	if len(vs.Misc) > 0 {
    76  		vs.Misc = map[string]interface{}{}
    77  	}
    78  }
    79  
    80  // SetEvaluatedKey updates the evaluation properties of the current state
    81  func (vs *ValidationState) SetEvaluatedKey(key string) {
    82  	(*vs.EvaluatedPropertyNames)[key] = true
    83  	(*vs.LocalEvaluatedPropertyNames)[key] = true
    84  }
    85  
    86  // IsEvaluatedKey checks if the key is evaluated against the state context
    87  func (vs *ValidationState) IsEvaluatedKey(key string) bool {
    88  	_, ok := (*vs.EvaluatedPropertyNames)[key]
    89  	return ok
    90  }
    91  
    92  // IsLocallyEvaluatedKey checks if the key is evaluated against the local state context
    93  func (vs *ValidationState) IsLocallyEvaluatedKey(key string) bool {
    94  	_, ok := (*vs.LocalEvaluatedPropertyNames)[key]
    95  	return ok
    96  }
    97  
    98  // SetEvaluatedIndex sets the evaluation index for the current state
    99  func (vs *ValidationState) SetEvaluatedIndex(i int) {
   100  	vs.LastEvaluatedIndex = i
   101  	vs.LocalLastEvaluatedIndex = i
   102  }
   103  
   104  // UpdateEvaluatedPropsAndItems is a utility function to join evaluated properties and set the
   105  // current evaluation position index
   106  func (vs *ValidationState) UpdateEvaluatedPropsAndItems(subState *ValidationState) {
   107  	joinSets(vs.EvaluatedPropertyNames, *subState.EvaluatedPropertyNames)
   108  	joinSets(vs.LocalEvaluatedPropertyNames, *subState.LocalEvaluatedPropertyNames)
   109  	if subState.LastEvaluatedIndex > vs.LastEvaluatedIndex {
   110  		vs.LastEvaluatedIndex = subState.LastEvaluatedIndex
   111  	}
   112  	if subState.LocalLastEvaluatedIndex > vs.LastEvaluatedIndex {
   113  		vs.LastEvaluatedIndex = subState.LocalLastEvaluatedIndex
   114  	}
   115  }
   116  
   117  func copySet(input map[string]bool) map[string]bool {
   118  	copy := make(map[string]bool, len(input))
   119  	for k, v := range input {
   120  		copy[k] = v
   121  	}
   122  	return copy
   123  }
   124  
   125  func joinSets(consumer *map[string]bool, supplier map[string]bool) {
   126  	for k, v := range supplier {
   127  		(*consumer)[k] = v
   128  	}
   129  }
   130  
   131  // AddError creates and appends a KeyError to errs of the current state
   132  func (vs *ValidationState) AddError(data interface{}, msg string) {
   133  	schemaDebug("[AddError] Error: %s", msg)
   134  	instancePath := vs.InstanceLocation.String()
   135  	if len(instancePath) == 0 {
   136  		instancePath = "/"
   137  	}
   138  	*vs.Errs = append(*vs.Errs, KeyError{
   139  		PropertyPath: instancePath,
   140  		InvalidValue: data,
   141  		Message:      msg,
   142  	})
   143  }
   144  
   145  // AddSubErrors appends a list of KeyError to the current state
   146  func (vs *ValidationState) AddSubErrors(errs ...KeyError) {
   147  	for _, err := range errs {
   148  		schemaDebug("[AddSubErrors] Error: %s", err.Message)
   149  	}
   150  	*vs.Errs = append(*vs.Errs, errs...)
   151  }
   152  
   153  // IsValid returns if the current state is valid
   154  func (vs *ValidationState) IsValid() bool {
   155  	if vs.Errs == nil {
   156  		return true
   157  	}
   158  	return len(*vs.Errs) == 0
   159  }
   160  
   161  // DescendBase descends the base relative pointer relative to itself
   162  func (vs *ValidationState) DescendBase(token ...string) {
   163  	vs.DescendBaseFromState(vs, token...)
   164  }
   165  
   166  // DescendBaseFromState descends the base relative pointer relative to the provided state
   167  func (vs *ValidationState) DescendBaseFromState(base *ValidationState, token ...string) {
   168  	if base.BaseRelativeLocation != nil {
   169  		newPtr := base.BaseRelativeLocation.RawDescendant(token...)
   170  		vs.BaseRelativeLocation = &newPtr
   171  	}
   172  }
   173  
   174  // DescendRelative descends the relative pointer relative to itself
   175  func (vs *ValidationState) DescendRelative(token ...string) {
   176  	vs.DescendRelativeFromState(vs, token...)
   177  }
   178  
   179  // DescendRelativeFromState descends the relative pointer relative to the provided state
   180  func (vs *ValidationState) DescendRelativeFromState(base *ValidationState, token ...string) {
   181  	newPtr := base.InstanceLocation.RawDescendant(token...)
   182  	vs.RelativeLocation = &newPtr
   183  }
   184  
   185  // DescendInstance descends the instance pointer relative to itself
   186  func (vs *ValidationState) DescendInstance(token ...string) {
   187  	vs.DescendInstanceFromState(vs, token...)
   188  }
   189  
   190  // DescendInstanceFromState descends the instance pointer relative to the provided state
   191  func (vs *ValidationState) DescendInstanceFromState(base *ValidationState, token ...string) {
   192  	newPtr := base.InstanceLocation.RawDescendant(token...)
   193  	vs.InstanceLocation = &newPtr
   194  }
   195  

View as plain text