コード例 #1
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (depth == InitialDepth && JsonTokenHelpers.IsPrimitiveOrEndToken(token))
            {
                if (!GetChildren().All(IsValidPredicate))
                {
                    List <int> invalidIndexes = new List <int>();
                    int        index          = 0;
                    foreach (SchemaScope schemaScope in GetChildren())
                    {
                        if (!schemaScope.IsValid)
                        {
                            invalidIndexes.Add(index);
                        }

                        index++;
                    }

                    IFormattable message = $"JSON does not match all schemas from 'allOf'. Invalid schema indexes: {StringHelpers.Join(", ", invalidIndexes)}.";
                    RaiseError(message, ErrorType.AllOf, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                return(true);
            }

            return(false);
        }
コード例 #2
0
        protected void EnsureEnum(JsonToken token, object value)
        {
            if (Schema._enum != null && Schema._enum.Count > 0)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    if (Context.TokenWriter == null)
                    {
                        Context.TokenWriter = new JTokenWriter();
                        Context.TokenWriter.WriteToken(token, value);
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token))
                {
                    if (!Schema._enum.ContainsValue(Context.TokenWriter.CurrentToken, JToken.EqualityComparer))
                    {
                        StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                        Context.TokenWriter.CurrentToken.WriteTo(new JsonTextWriter(sw));

                        RaiseError("Value {0} is not defined in enum.".FormatWith(CultureInfo.InvariantCulture, sw.ToString()), ErrorType.Enum, Schema, value, null);
                    }
                }
            }
        }
コード例 #3
0
        protected void EnsureEnum(JsonToken token, object value)
        {
            bool isEnum       = !Schema._enum.IsNullOrEmpty();
            bool hasConst     = Schema.Const != null;
            bool hasValidator = !Schema._validators.IsNullOrEmpty();

            if (isEnum || hasConst || hasValidator)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    if (Context.TokenWriter == null)
                    {
                        Context.TokenWriter = new JTokenWriter();
                        Context.TokenWriter.WriteToken(token, value);
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token))
                {
                    JToken currentToken = Context.TokenWriter.CurrentToken;

                    if (isEnum)
                    {
                        bool defined = JsonTokenHelpers.Contains(Schema._enum, currentToken);

                        if (!defined)
                        {
                            StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                            currentToken.WriteTo(new JsonTextWriter(sw));

                            RaiseError($"Value {sw.ToString()} is not defined in enum.", ErrorType.Enum, Schema, value, null);
                        }
                    }

                    if (hasConst)
                    {
                        bool defined = Schema.Const.DeepEquals(currentToken);

                        if (!defined)
                        {
                            StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                            currentToken.WriteTo(new JsonTextWriter(sw));

                            RaiseError($"Value {sw.ToString()} does not match const.", ErrorType.Const, Schema, value, null);
                        }
                    }

                    if (hasValidator)
                    {
                        JsonValidatorContext context = new JsonValidatorContext(this, Schema);

                        foreach (JsonValidator validator in Schema._validators)
                        {
                            validator.Validate(currentToken, context);
                        }
                    }
                }
            }
        }
コード例 #4
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (depth == InitialDepth && JsonTokenHelpers.IsPrimitiveOrEndToken(token))
            {
                if (GetChildrenAnyValid())
                {
                    RaiseError($"JSON is valid against schema from 'not'.", ErrorType.Not, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                return(true);
            }

            return(false);
        }
コード例 #5
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (depth == InitialDepth && JsonTokenHelpers.IsPrimitiveOrEndToken(token))
            {
                if (!GetChildren().Any(IsValidPredicate))
                {
                    RaiseError($"JSON does not match any schemas from 'anyOf'.", ErrorType.AnyOf, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                return(true);
            }

            return(false);
        }
コード例 #6
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (depth == InitialDepth && JsonTokenHelpers.IsPrimitiveOrEndToken(token))
            {
                int validCount = GetChildrenValidCount();

                if (validCount != 1)
                {
                    List <int> validIndexes = new List <int>();
                    int        index        = 0;
                    foreach (SchemaScope schemaScope in ChildScopes)
                    {
                        if (schemaScope.IsValid)
                        {
                            validIndexes.Add(index);
                        }

                        index++;
                    }

                    IFormattable message;
                    if (validIndexes.Count > 0)
                    {
                        message = $"JSON is valid against more than one schema from 'oneOf'. Valid schema indexes: {StringHelpers.Join(", ", validIndexes)}.";
                    }
                    else
                    {
                        message = $"JSON is valid against no schemas from 'oneOf'.";
                    }

                    RaiseError(message, ErrorType.OneOf, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                return(true);
            }

            return(false);
        }
コード例 #7
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (depth == InitialDepth && JsonTokenHelpers.IsPrimitiveOrEndToken(token))
            {
                int validCount = GetChildren().Count(IsValidPredicate);

                if (validCount != 1)
                {
                    List <int> validIndexes = new List <int>();
                    int        index        = 0;
                    foreach (SchemaScope schemaScope in GetChildren())
                    {
                        if (schemaScope.IsValid)
                        {
                            validIndexes.Add(index);
                        }

                        index++;
                    }

                    string message = "JSON is valid against more than one schema from 'oneOf'. ";
                    if (validIndexes.Count > 0)
                    {
                        message += "Valid schema indexes: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", validIndexes));
                    }
                    else
                    {
                        message += "No valid schemas.";
                    }

                    RaiseError(message, ErrorType.OneOf, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                return(true);
            }

            return(false);
        }
コード例 #8
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartObject:
                    TestType(Schema, JSchemaType.Object);
                    return(false);

                case JsonToken.EndObject:
                    if (!Schema._required.IsNullOrEmpty() && _requiredProperties.Count > 0)
                    {
                        RaiseError($"Required properties are missing from object: {StringHelpers.Join(", ", _requiredProperties)}.", ErrorType.Required, Schema, _requiredProperties, null);
                    }

                    if (Schema.MaximumProperties != null && _propertyCount > Schema.MaximumProperties)
                    {
                        RaiseError($"Object property count {_propertyCount} exceeds maximum count of {Schema.MaximumProperties}.", ErrorType.MaximumProperties, Schema, _propertyCount, null);
                    }

                    if (Schema.MinimumProperties != null && _propertyCount < Schema.MinimumProperties)
                    {
                        RaiseError($"Object property count {_propertyCount} is less than minimum count of {Schema.MinimumProperties}.", ErrorType.MinimumProperties, Schema, _propertyCount, null);
                    }

                    if (!Schema._dependencies.IsNullOrEmpty())
                    {
                        foreach (string readProperty in _readProperties)
                        {
                            object dependency;
                            if (Schema._dependencies.TryGetValue(readProperty, out dependency))
                            {
                                List <string> requiredProperties = dependency as List <string>;
                                if (requiredProperties != null)
                                {
                                    if (!requiredProperties.All(r => _readProperties.Contains(r)))
                                    {
                                        IEnumerable <string> missingRequiredProperties = requiredProperties.Where(r => !_readProperties.Contains(r));
                                        IFormattable         message = $"Dependencies for property '{readProperty}' failed. Missing required keys: {StringHelpers.Join(", ", missingRequiredProperties)}.";

                                        RaiseError(message, ErrorType.Dependencies, Schema, readProperty, null);
                                    }
                                }
                                else
                                {
                                    SchemaScope dependencyScope = _dependencyScopes[readProperty];
                                    if (dependencyScope.Context.HasErrors)
                                    {
                                        IFormattable message = $"Dependencies for property '{readProperty}' failed.";
                                        RaiseError(message, ErrorType.Dependencies, Schema, readProperty, ((ConditionalContext)dependencyScope.Context).Errors);
                                    }
                                }
                            }
                        }
                    }

                    if (Schema._patternProperties != null)
                    {
                        foreach (PatternSchema patternSchema in Schema.GetPatternSchemas())
                        {
                            Regex  regex;
                            string errorMessage;
                            if (!patternSchema.TryGetPatternRegex(out regex, out errorMessage))
                            {
                                RaiseError($"Could not test property names with regex pattern '{patternSchema.Pattern}'. There was an error parsing the regex: {errorMessage}",
                                           ErrorType.PatternProperties,
                                           Schema,
                                           patternSchema.Pattern,
                                           null);
                            }
                        }
                    }
                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating object: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (token == JsonToken.PropertyName)
                {
                    _propertyCount++;
                    _currentPropertyName = (string)value;

                    if (!Schema._required.IsNullOrEmpty())
                    {
                        _requiredProperties.Remove(_currentPropertyName);
                    }
                    if (!Schema._dependencies.IsNullOrEmpty())
                    {
                        _readProperties.Add(_currentPropertyName);
                    }

                    if (!Schema.AllowAdditionalProperties)
                    {
                        if (!IsPropertyDefinied(Schema, _currentPropertyName))
                        {
                            IFormattable message = $"Property '{_currentPropertyName}' has not been defined and the schema does not allow additional properties.";
                            RaiseError(message, ErrorType.AdditionalProperties, Schema, _currentPropertyName, null);
                        }
                    }
                }
                else
                {
                    if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                    {
                        bool matched = false;
                        if (Schema._properties != null)
                        {
                            JSchema propertySchema;
                            if (Schema._properties.TryGetValue(_currentPropertyName, out propertySchema))
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, propertySchema);
                                matched = true;
                            }
                        }

                        if (Schema._patternProperties != null)
                        {
                            foreach (PatternSchema patternProperty in Schema.GetPatternSchemas())
                            {
                                Regex  regex;
                                string errorMessage;
                                if (patternProperty.TryGetPatternRegex(out regex, out errorMessage))
                                {
                                    if (regex.IsMatch(_currentPropertyName))
                                    {
                                        CreateScopesAndEvaluateToken(token, value, depth, patternProperty.Schema);
                                        matched = true;
                                    }
                                }
                            }
                        }

                        if (!matched)
                        {
                            if (Schema.AllowAdditionalProperties && Schema.AdditionalProperties != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalProperties);
                            }
                        }
                    }
                }
            }

            return(false);
        }
コード例 #9
0
        protected void EnsureEnum(JsonToken token, object?value)
        {
            bool isEnum       = !Schema._enum.IsNullOrEmpty();
            bool hasConst     = Schema.Const != null;
            bool hasValidator = !Schema._validators.IsNullOrEmpty();

            if (isEnum || hasConst || hasValidator)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    if (Context.TokenWriter == null)
                    {
                        Context.TokenWriter = new JTokenWriter();
                        Context.TokenWriter.WriteToken(token, value);
                    }
                }
                else if (token == JsonToken.PropertyName)
                {
                    if (Context.TokenWriter == null)
                    {
                        Context.TokenWriter = new JTokenWriter();
                        Context.TokenWriter.WriteToken(JsonToken.String, value);
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token) || token == JsonToken.PropertyName)
                {
                    ValidationUtils.Assert(Context.TokenWriter != null);

                    JToken currentToken = Context.TokenWriter.CurrentToken !;

                    if (isEnum)
                    {
                        JToken resolvedToken = (currentToken is JProperty property)
                            ? new JValue(property.Name)
                            : currentToken;

                        bool defined = JsonTokenHelpers.Contains(Schema._enum !, resolvedToken);

                        if (!defined)
                        {
                            StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                            currentToken.WriteTo(new JsonTextWriter(sw));

                            RaiseError($"Value {sw.ToString()} is not defined in enum.", ErrorType.Enum, Schema, value, null);
                        }
                    }

                    if (hasConst)
                    {
                        bool defined = JsonTokenHelpers.ImplicitDeepEquals(Schema.Const !, currentToken);

                        if (!defined)
                        {
                            StringWriter sw = new StringWriter(CultureInfo.InvariantCulture);
                            currentToken.WriteTo(new JsonTextWriter(sw));

                            RaiseError($"Value {sw.ToString()} does not match const.", ErrorType.Const, Schema, value, null);
                        }
                    }

                    if (hasValidator)
                    {
                        JsonValidatorContext context = new JsonValidatorContext(this, Schema);

                        foreach (JsonValidator validator in Schema._validators !)
                        {
                            validator.Validate(currentToken, context);
                        }
                    }
                }
            }
        }
コード例 #10
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartArray:
                    EnsureValid(value);
                    TestType(Schema, JSchemaType.Array);
                    return(false);

                case JsonToken.StartConstructor:
                    JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None);

                    if (schemaType != JSchemaType.None)
                    {
                        RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null);
                    }
                    return(false);

                case JsonToken.EndArray:
                case JsonToken.EndConstructor:
                    ValidateConditionalChildren(token, value, depth);

                    int itemCount = _index + 1;

                    if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems)
                    {
                        RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null);
                    }

                    if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems)
                    {
                        RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null);
                    }

                    if (Schema.Contains != null)
                    {
                        // MinimumContains overrides default contains behavior
                        if (Schema.MinimumContains != null)
                        {
                            if (_matchCount < Schema.MinimumContains)
                            {
                                RaiseError($"Contains match count {_matchCount} is less than minimum contains count of {Schema.MinimumContains}.", ErrorType.MinimumContains, Schema, null, GetValidationErrors(_containsContexts));
                            }
                        }
                        else
                        {
                            if (_matchCount == 0)
                            {
                                RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, GetValidationErrors(_containsContexts));
                            }
                        }

                        if (_matchCount > Schema.MaximumContains)
                        {
                            RaiseError($"Contains match count {_matchCount} exceeds maximum contains count of {Schema.MaximumContains}.", ErrorType.MaximumContains, Schema, null, GetValidationErrors(_containsContexts));
                        }
                    }

                    if (!_unevaluatedScopes.IsNullOrEmpty())
                    {
                        foreach (KeyValuePair <int, UnevaluatedContext> item in _unevaluatedScopes)
                        {
                            if (!item.Value.Evaluated)
                            {
                                IFormattable message = $"Item at index {item.Key} has not been successfully evaluated and the schema does not allow unevaluated items.";
                                RaiseError(message, ErrorType.UnevaluatedItems, Schema, item.Key, item.Value.SchemaScope.GetValidationErrors());
                            }
                        }
                    }

                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating array: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    _index++;

                    if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty())
                    {
                        if (Context.TokenWriter == null)
                        {
                            Context.TokenWriter = new JTokenWriter();
                            Context.TokenWriter.WriteToken(token, value);
                        }
                    }

                    bool matched = false;

                    if (Schema.ItemsPositionValidation)
                    {
                        // TODO: Remove LINQ
                        JSchema itemSchema = Schema._items?.ElementAtOrDefault(_index);

                        if (itemSchema != null)
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, itemSchema);
                            matched = true;
                        }
                        else
                        {
                            if (!Schema.AllowAdditionalItems)
                            {
                                RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null);
                            }
                            else if (Schema.AdditionalItems != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems);
                                matched = true;
                            }
                        }
                    }
                    else
                    {
                        if (!Schema._items.IsNullOrEmpty())
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]);
                            matched = true;
                        }
                    }

                    if (ShouldEvaluateContains())
                    {
                        ConditionalContext containsContext = CreateConditionalContext();
                        _containsContexts.Add(containsContext);

                        // contains scope should not have the current scope the parent
                        // do not want contain failures setting the current scope's IsValid
                        CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains, null, containsContext);
                    }

                    if (!matched)
                    {
                        if (ShouldValidateUnevaluated())
                        {
                            _unevaluatedScopes[_index] = Schema.UnevaluatedItems != null
                                ? new UnevaluatedContext(CreateScopesAndEvaluateToken(token, value, depth, Schema.UnevaluatedItems, this, CreateConditionalContext()))
                                : new UnevaluatedContext(AlwaysFalseScope.Instance);
                        }
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token))
                {
                    if (Schema.UniqueItems)
                    {
                        JToken currentToken = Context.TokenWriter.CurrentToken;
                        bool   isDuplicate  = JsonTokenHelpers.Contains(_uniqueArrayItems, currentToken);
                        if (isDuplicate)
                        {
                            object v = (currentToken is JValue valueToken) ? valueToken.Value : currentToken;

                            RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null);
                        }
                        else
                        {
                            _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken);
                        }
                    }

                    if (ShouldEvaluateContains())
                    {
                        ConditionalContext currentContainsContext = _containsContexts[_containsContexts.Count - 1];
                        if (!currentContainsContext.HasErrors)
                        {
                            _matchCount++;
                        }
                    }

                    if (ShouldValidateUnevaluated() &&
                        _unevaluatedScopes.TryGetValue(_index, out UnevaluatedContext unevaluatedContext))
                    {
                        // Property is valid against unevaluatedItems schema so no need to search further
                        bool isValid = unevaluatedContext.SchemaScope.IsValid;
                        unevaluatedContext.Evaluated = isValid;

                        if (!isValid)
                        {
                            for (int i = Context.Scopes.Count - 1; i >= 0; i--)
                            {
                                Scope scope = Context.Scopes[i];
                                if (scope.InitialDepth == InitialDepth + 1)
                                {
                                    // Schema for a item
                                    if (scope.Parent != null && scope is SchemaScope schemaScope && schemaScope.IsValid)
                                    {
                                        unevaluatedContext.AddValidScope(schemaScope.Parent.Schema);
                                    }
                                }
                                else if (scope.InitialDepth == InitialDepth)
                                {
                                    // Schema for the current array.
                                    // Need to check these for oneOf, allOf, etc.
                                    if (scope is SchemaScope schemaScope)
                                    {
                                        if (schemaScope.Schema._allowAdditionalItems.GetValueOrDefault() ||
                                            schemaScope.Schema.AdditionalItems != null ||
                                            schemaScope.Schema.AllowUnevaluatedItems.GetValueOrDefault())
                                        {
                                            unevaluatedContext.AddValidScope(schemaScope.Schema);
                                        }
                                    }
                                }
                                else if (scope.InitialDepth < InitialDepth)
                                {
                                    break;
                                }
                            }
                        }
                    }
                }
            }

            return(false);
        }
コード例 #11
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartArray:
                    EnsureValid(value);
                    TestType(Schema, JSchemaType.Array);
                    return(false);

                case JsonToken.StartConstructor:
                    JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None);

                    if (schemaType != JSchemaType.None)
                    {
                        RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null);
                    }
                    return(false);

                case JsonToken.EndArray:
                case JsonToken.EndConstructor:
                    ValidateConditionalChildren(token, value, depth);

                    int itemCount = _index + 1;

                    if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems)
                    {
                        RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null);
                    }

                    if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems)
                    {
                        RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null);
                    }

                    if (Schema.Contains != null && !_matchContains)
                    {
                        List <ValidationError> containsErrors = new List <ValidationError>();
                        foreach (ConditionalContext containsContext in _containsContexts)
                        {
                            containsErrors.AddRange(containsContext.Errors);
                        }

                        RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, containsErrors);
                    }

                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating array: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    _index++;

                    if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty())
                    {
                        if (Context.TokenWriter == null)
                        {
                            Context.TokenWriter = new JTokenWriter();
                            Context.TokenWriter.WriteToken(token, value);
                        }
                    }

                    if (Schema.ItemsPositionValidation)
                    {
                        JSchema itemSchema = Schema._items?.ElementAtOrDefault(_index);

                        if (itemSchema != null)
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, itemSchema);
                        }
                        else
                        {
                            if (!Schema.AllowAdditionalItems)
                            {
                                RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null);
                            }
                            else if (Schema.AdditionalItems != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems);
                            }
                        }
                    }
                    else
                    {
                        if (!Schema._items.IsNullOrEmpty())
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]);
                        }
                    }

                    // no longer need to check contains schema after match
                    if (Schema.Contains != null && !_matchContains)
                    {
                        ConditionalContext containsContext = ConditionalContext.Create(Context);
                        _containsContexts.Add(containsContext);

                        // contains scope should not have the current scope the parent
                        // do not want contain failures setting the current scope's IsValid
                        CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains, null, containsContext);
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token))
                {
                    if (Schema.UniqueItems)
                    {
                        JToken currentToken = Context.TokenWriter.CurrentToken;
                        bool   isDuplicate  = JsonTokenHelpers.Contains(_uniqueArrayItems, currentToken);
                        if (isDuplicate)
                        {
                            object v = (currentToken is JValue valueToken) ? valueToken.Value : currentToken;

                            RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null);
                        }
                        else
                        {
                            _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken);
                        }
                    }

                    if (Schema.Contains != null && !_matchContains)
                    {
                        ConditionalContext currentContainsContext = _containsContexts[_containsContexts.Count - 1];
                        if (!currentContainsContext.HasErrors)
                        {
                            _matchContains = true;

                            // no longer need previous errors after match
                            _containsContexts.Clear();
                        }
                    }
                }
            }

            return(false);
        }
コード例 #12
0
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartObject:
                    EnsureValid(value);
                    TestType(Schema, JSchemaType.Object);
                    return(false);

                case JsonToken.EndObject:
                    ValidateConditionalChildren(token, value, depth);

                    if (!Schema._required.IsNullOrEmpty() && _requiredProperties !.Count > 0)
                    {
                        //capture required properties at current depth as we may clear _requiredProperties later on
                        List <string> capturedRequiredProperties = _requiredProperties.ToList();
                        RaiseError($"Required properties are missing from object: {StringHelpers.Join(", ", capturedRequiredProperties)}.", ErrorType.Required, Schema, capturedRequiredProperties, null);
                    }

                    if (Schema.MaximumProperties != null && _propertyCount > Schema.MaximumProperties)
                    {
                        RaiseError($"Object property count {_propertyCount} exceeds maximum count of {Schema.MaximumProperties}.", ErrorType.MaximumProperties, Schema, _propertyCount, null);
                    }

                    if (Schema.MinimumProperties != null && _propertyCount < Schema.MinimumProperties)
                    {
                        RaiseError($"Object property count {_propertyCount} is less than minimum count of {Schema.MinimumProperties}.", ErrorType.MinimumProperties, Schema, _propertyCount, null);
                    }

                    if (HasDependencies())
                    {
                        foreach (string readProperty in _readProperties !)
                        {
                            object?        dependency         = null;
                            IList <string>?requiredProperties = null;
                            if (Schema._dependencies?.TryGetValue(readProperty, out dependency) ?? false)
                            {
                                requiredProperties = dependency as IList <string>;
                                if (requiredProperties != null)
                                {
                                    ValidateDependantProperties(readProperty, requiredProperties);
                                }
                                else
                                {
                                    ValidateDependantSchema(readProperty);
                                }
                            }

                            if (Schema._dependentRequired?.TryGetValue(readProperty, out requiredProperties) ?? false)
                            {
                                ValidateDependantProperties(readProperty, requiredProperties !);
                            }

                            if (Schema._dependentSchemas?.TryGetValue(readProperty, out _) ?? false)
                            {
                                ValidateDependantSchema(readProperty);
                            }
                        }
                    }

                    // Evaluate after dependency schemas have been validated
                    if (!_unevaluatedScopes.IsNullOrEmpty())
                    {
                        foreach (KeyValuePair <string, UnevaluatedContext> item in _unevaluatedScopes)
                        {
                            if (!item.Value.Evaluated)
                            {
                                IFormattable message = $"Property '{item.Key}' has not been successfully evaluated and the schema does not allow unevaluated properties.";
                                RaiseError(message, ErrorType.UnevaluatedProperties, Schema, item.Key, item.Value.SchemaScope.GetValidationErrors());
                            }
                        }
                    }

                    if (Schema._patternProperties != null)
                    {
                        foreach (PatternSchema patternSchema in Schema.GetPatternSchemas())
                        {
                            if (!patternSchema.TryGetPatternRegex(
#if !(NET35 || NET40)
                                    Context.Validator.RegexMatchTimeout,
#endif
                                    out Regex? _,
                                    out string?errorMessage))
                            {
                                RaiseError($"Could not test property names with regex pattern '{patternSchema.Pattern}'. There was an error parsing the regex: {errorMessage}",
                                           ErrorType.PatternProperties,
                                           Schema,
                                           patternSchema.Pattern,
                                           null);
                            }
                        }
                    }

                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating object: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (token == JsonToken.PropertyName)
                {
                    _propertyCount++;
                    _currentPropertyName = (string)value !;

                    if (!Schema._required.IsNullOrEmpty())
                    {
                        _requiredProperties !.Remove(_currentPropertyName);
                    }
                    if (HasDependencies())
                    {
                        _readProperties !.Add(_currentPropertyName);
                    }

                    if (Schema._propertyNames != null)
                    {
                        CreateScopesAndEvaluateToken(token, value, depth, Schema._propertyNames);
                    }

                    if (!Schema.AllowAdditionalProperties)
                    {
                        if (!IsPropertyDefined(Schema, _currentPropertyName))
                        {
                            IFormattable message = $"Property '{_currentPropertyName}' has not been defined and the schema does not allow additional properties.";
                            RaiseError(message, ErrorType.AdditionalProperties, Schema, _currentPropertyName, null);
                        }
                    }
                }
                else
                {
                    ValidationUtils.Assert(_currentPropertyName != null);

                    if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                    {
                        bool matched = false;
                        if (Schema._properties != null)
                        {
                            if (Schema._properties.TryGetValue(_currentPropertyName, out JSchema propertySchema))
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, propertySchema);
                                matched = true;
                            }
                        }

                        if (Schema._patternProperties != null)
                        {
                            foreach (PatternSchema patternProperty in Schema.GetPatternSchemas())
                            {
                                if (patternProperty.TryGetPatternRegex(
#if !(NET35 || NET40)
                                        Context.Validator.RegexMatchTimeout,
#endif
                                        out Regex? regex,
                                        out string?_))
                                {
                                    if (RegexHelpers.IsMatch(regex, patternProperty.Pattern, _currentPropertyName))
                                    {
                                        CreateScopesAndEvaluateToken(token, value, depth, patternProperty.Schema);
                                        matched = true;
                                    }
                                }
                            }
                        }

                        if (!matched)
                        {
                            if (Schema.AllowAdditionalProperties && Schema.AdditionalProperties != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalProperties);
                            }

                            if (ShouldValidateUnevaluated())
                            {
                                _unevaluatedScopes ![_currentPropertyName] = Schema.UnevaluatedProperties != null
コード例 #13
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartArray:
                    TestType(Schema, JSchemaType.Array, null);
                    return(false);

                case JsonToken.StartConstructor:
                    RaiseError($"Invalid type. Expected {Schema.Type} but got Constructor.", ErrorType.Type, Schema, value, null);
                    return(false);

                case JsonToken.EndArray:
                case JsonToken.EndConstructor:
                    int itemCount = _index + 1;

                    if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems)
                    {
                        RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null);
                    }

                    if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems)
                    {
                        RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null);
                    }

                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating array: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    _index++;

                    if (Schema.UniqueItems)
                    {
                        if (Context.TokenWriter == null)
                        {
                            Context.TokenWriter = new JTokenWriter();
                            Context.TokenWriter.WriteToken(token, value);
                        }
                    }

                    if (Schema.ItemsPositionValidation)
                    {
                        JSchema itemSchema = (Schema._items != null)
                            ? Schema._items.ElementAtOrDefault(_index)
                            : null;

                        if (itemSchema != null)
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, itemSchema);
                        }
                        else
                        {
                            if (!Schema.AllowAdditionalItems)
                            {
                                RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null);
                            }
                            else if (Schema.AdditionalItems != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems);
                            }
                        }
                    }
                    else
                    {
                        if (Schema._items != null && Schema._items.Count > 0)
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]);
                        }
                    }
                }

                if (JsonTokenHelpers.IsPrimitiveOrEndToken(token))
                {
                    if (Schema.UniqueItems)
                    {
                        var currentToken = Context.TokenWriter.CurrentToken;
                        if (_uniqueArrayItems.Contains(currentToken, JToken.EqualityComparer))
                        {
                            object v = (currentToken is JValue) ? ((JValue)currentToken).Value : currentToken;

                            RaiseError($"Non-unique array item at index {_index}.", ErrorType.UniqueItems, Schema, v, null);
                        }
                        else
                        {
                            _uniqueArrayItems.Add(Context.TokenWriter.CurrentToken);
                        }
                    }
                }
            }

            return(false);
        }
コード例 #14
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartObject:
                    TestType(Schema, JSchemaType.Object, null);
                    return(false);

                case JsonToken.EndObject:
                    if (_requiredProperties != null && _requiredProperties.Count > 0)
                    {
                        RaiseError("Required properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", _requiredProperties)), ErrorType.Required, Schema, _requiredProperties, null);
                    }

                    if (Schema.MaximumProperties != null && _propertyCount > Schema.MaximumProperties)
                    {
                        RaiseError("Object property count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, _propertyCount, Schema.MaximumProperties), ErrorType.MaximumProperties, Schema, _propertyCount, null);
                    }

                    if (Schema.MinimumProperties != null && _propertyCount < Schema.MinimumProperties)
                    {
                        RaiseError("Object property count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, _propertyCount, Schema.MinimumProperties), ErrorType.MinimumProperties, Schema, _propertyCount, null);
                    }

                    if (_readProperties != null)
                    {
                        foreach (string readProperty in _readProperties)
                        {
                            object dependency;
                            if (Schema._dependencies.TryGetValue(readProperty, out dependency))
                            {
                                List <string> requiredProperties = dependency as List <string>;
                                if (requiredProperties != null)
                                {
                                    if (!requiredProperties.All(r => _readProperties.Contains(r)))
                                    {
                                        List <string> missingRequiredProperties = requiredProperties.Where(r => !_readProperties.Contains(r)).ToList();
                                        string        message = "Dependencies for property '{0}' failed. Missing required keys: {1}.".FormatWith(CultureInfo.InvariantCulture, readProperty, string.Join(", ", missingRequiredProperties));

                                        RaiseError(message, ErrorType.Dependencies, Schema, readProperty, null);
                                    }
                                }
                                else
                                {
                                    SchemaScope dependencyScope = _dependencyScopes[readProperty];
                                    if (dependencyScope.Context.HasErrors)
                                    {
                                        string message = "Dependencies for property '{0}' failed.".FormatWith(CultureInfo.InvariantCulture, readProperty);
                                        RaiseError(message, ErrorType.Dependencies, Schema, readProperty, ((ConditionalContext)dependencyScope.Context).Errors);
                                    }
                                }
                            }
                        }
                    }
                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating object: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (token == JsonToken.PropertyName)
                {
                    _propertyCount++;
                    _currentPropertyName = (string)value;

                    if (_requiredProperties != null)
                    {
                        _requiredProperties.Remove(_currentPropertyName);
                    }
                    if (_readProperties != null)
                    {
                        _readProperties.Add(_currentPropertyName);
                    }

                    if (!Schema.AllowAdditionalProperties)
                    {
                        if (!IsPropertyDefinied(Schema, _currentPropertyName))
                        {
                            string message = "Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, _currentPropertyName);
                            RaiseError(message, ErrorType.AdditionalProperties, Schema, _currentPropertyName, null);
                        }
                    }
                }
                else
                {
                    if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                    {
                        bool matched = false;
                        if (Schema._properties != null)
                        {
                            JSchema propertySchema;
                            if (Schema._properties.TryGetValue(_currentPropertyName, out propertySchema))
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, propertySchema);
                                matched = true;
                            }
                        }

                        if (Schema._patternProperties != null)
                        {
                            foreach (KeyValuePair <string, JSchema> patternProperty in Schema._patternProperties)
                            {
                                if (Regex.IsMatch(_currentPropertyName, patternProperty.Key))
                                {
                                    CreateScopesAndEvaluateToken(token, value, depth, patternProperty.Value);
                                    matched = true;
                                }
                            }
                        }

                        if (!matched)
                        {
                            if (Schema.AllowAdditionalProperties && Schema.AdditionalProperties != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalProperties);
                            }
                        }
                    }
                }
            }

            return(false);
        }
コード例 #15
0
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            int relativeDepth = depth - InitialDepth;

            if (relativeDepth == 0)
            {
                EnsureEnum(token, value);

                switch (token)
                {
                case JsonToken.StartArray:
                    EnsureValid(value);
                    TestType(Schema, JSchemaType.Array);
                    return(false);

                case JsonToken.StartConstructor:
                    JSchemaType schemaType = Schema.Type.GetValueOrDefault(JSchemaType.None);

                    if (schemaType != JSchemaType.None)
                    {
                        RaiseError($"Invalid type. Expected {schemaType.GetDisplayText()} but got Constructor.", ErrorType.Type, Schema, value, null);
                    }
                    return(false);

                case JsonToken.EndArray:
                case JsonToken.EndConstructor:
                    ValidateConditionalChildren(token, value, depth);

                    int itemCount = _index + 1;

                    if (Schema.MaximumItems != null && itemCount > Schema.MaximumItems)
                    {
                        RaiseError($"Array item count {itemCount} exceeds maximum count of {Schema.MaximumItems}.", ErrorType.MaximumItems, Schema, itemCount, null);
                    }

                    if (Schema.MinimumItems != null && itemCount < Schema.MinimumItems)
                    {
                        RaiseError($"Array item count {itemCount} is less than minimum count of {Schema.MinimumItems}.", ErrorType.MinimumItems, Schema, itemCount, null);
                    }

                    if (Schema.Contains != null)
                    {
                        ValidationUtils.Assert(_containsContexts != null);

                        // MinimumContains overrides default contains behavior
                        if (Schema.MinimumContains != null)
                        {
                            if (_matchCount < Schema.MinimumContains)
                            {
                                RaiseError($"Contains match count {_matchCount} is less than minimum contains count of {Schema.MinimumContains}.", ErrorType.MinimumContains, Schema, null, GetValidationErrors(_containsContexts));
                            }
                        }
                        else
                        {
                            if (_matchCount == 0)
                            {
                                RaiseError($"No items match contains.", ErrorType.Contains, Schema, null, GetValidationErrors(_containsContexts));
                            }
                        }

                        if (_matchCount > Schema.MaximumContains)
                        {
                            RaiseError($"Contains match count {_matchCount} exceeds maximum contains count of {Schema.MaximumContains}.", ErrorType.MaximumContains, Schema, null, GetValidationErrors(_containsContexts));
                        }
                    }

                    if (!_unevaluatedScopes.IsNullOrEmpty())
                    {
                        foreach (KeyValuePair <int, UnevaluatedContext> item in _unevaluatedScopes)
                        {
                            if (!item.Value.Evaluated)
                            {
                                IFormattable message = $"Item at index {item.Key} has not been successfully evaluated and the schema does not allow unevaluated items.";
                                RaiseError(message, ErrorType.UnevaluatedItems, Schema, item.Key, item.Value.SchemaScope.GetValidationErrors());
                            }
                        }
                    }

                    return(true);

                default:
                    throw new InvalidOperationException("Unexpected token when evaluating array: " + token);
                }
            }

            if (relativeDepth == 1)
            {
                if (JsonTokenHelpers.IsPrimitiveOrStartToken(token))
                {
                    _index++;

                    if (Schema.UniqueItems || !Schema._validators.IsNullOrEmpty())
                    {
                        if (Context.TokenWriter == null)
                        {
                            Context.TokenWriter = new JTokenWriter();
                            Context.TokenWriter.WriteToken(token, value);
                        }
                    }

                    bool matched = false;

                    if (Schema.ItemsPositionValidation)
                    {
                        // TODO: Remove LINQ
                        JSchema?itemSchema = Schema._items?.ElementAtOrDefault(_index);

                        if (itemSchema != null)
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, itemSchema);
                            matched = true;
                        }
                        else
                        {
                            if (!Schema.AllowAdditionalItems)
                            {
                                RaiseError($"Index {_index + 1} has not been defined and the schema does not allow additional items.", ErrorType.AdditionalItems, Schema, value, null);
                            }
                            else if (Schema.AdditionalItems != null)
                            {
                                CreateScopesAndEvaluateToken(token, value, depth, Schema.AdditionalItems);
                                matched = true;
                            }
                        }
                    }
                    else
                    {
                        if (!Schema._items.IsNullOrEmpty())
                        {
                            CreateScopesAndEvaluateToken(token, value, depth, Schema._items[0]);
                            matched = true;
                        }
                    }

                    if (ShouldEvaluateContains())
                    {
                        ConditionalContext containsContext = CreateConditionalContext();
                        _containsContexts.Add(containsContext);

                        // contains scope should not have the current scope the parent
                        // do not want contain failures setting the current scope's IsValid
                        CreateScopesAndEvaluateToken(token, value, depth, Schema.Contains !, null, containsContext);
                    }

                    if (!matched)
                    {
                        if (ShouldValidateUnevaluated())
                        {
                            _unevaluatedScopes ![_index] = Schema.UnevaluatedItems != null