@@ -15,6 +15,7 @@ import (
1515 "regexp"
1616 "strings"
1717
18+ "github.com/Masterminds/semver"
1819 "github.com/pkg/errors"
1920 "gopkg.in/yaml.v3"
2021
@@ -32,6 +33,9 @@ type Validator struct {
3233 // FieldDependencyManager resolves references to external fields
3334 FieldDependencyManager * DependencyManager
3435
36+ // SpecVersion contains the version of the spec used by the package.
37+ specVersion semver.Version
38+
3539 defaultNumericConversion bool
3640 numericKeywordFields map [string ]struct {}
3741
@@ -44,6 +48,18 @@ type Validator struct {
4448// ValidatorOption represents an optional flag that can be passed to CreateValidatorForDirectory.
4549type ValidatorOption func (* Validator ) error
4650
51+ // WithSpecVersion enables validation dependant of the spec version used by the package.
52+ func WithSpecVersion (version string ) ValidatorOption {
53+ return func (v * Validator ) error {
54+ sv , err := semver .NewVersion (version )
55+ if err != nil {
56+ return fmt .Errorf ("invalid version %q: %v" , version , err )
57+ }
58+ v .specVersion = * sv
59+ return nil
60+ }
61+ }
62+
4763// WithDefaultNumericConversion configures the validator to accept defined keyword (or constant_keyword) fields as numeric-type.
4864func WithDefaultNumericConversion () ValidatorOption {
4965 return func (v * Validator ) error {
@@ -255,7 +271,12 @@ func (v *Validator) validateScalarElement(key string, val interface{}) error {
255271 val = fmt .Sprintf ("%q" , val )
256272 }
257273
258- err := v .parseElementValue (key , * definition , val )
274+ err := v .validateExpectedNormalization (* definition , val )
275+ if err != nil {
276+ return errors .Wrapf (err , "field %q is not normalized as expected" , key )
277+ }
278+
279+ err = v .parseElementValue (key , * definition , val )
259280 if err != nil {
260281 return errors .Wrap (err , "parsing field value failed" )
261282 }
@@ -361,6 +382,22 @@ func compareKeys(key string, def FieldDefinition, searchedKey string) bool {
361382 return false
362383}
363384
385+ func (v * Validator ) validateExpectedNormalization (definition FieldDefinition , val interface {}) error {
386+ // Validate expected normalization starting with packages following spec v2 format.
387+ if v .specVersion .LessThan (semver .MustParse ("2.0.0" )) {
388+ return nil
389+ }
390+ for _ , normalize := range definition .Normalize {
391+ switch normalize {
392+ case "array" :
393+ if _ , isArray := val .([]interface {}); val != nil && ! isArray {
394+ return fmt .Errorf ("expected array, found %q (%T)" , val , val )
395+ }
396+ }
397+ }
398+ return nil
399+ }
400+
364401// validSubField checks if the extra part that didn't match with any field definition,
365402// matches with the possible sub field of complex fields like geo_point or histogram.
366403func validSubField (def FieldDefinition , extraPart string ) bool {
0 commit comments