Exemple #1
0
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            if (!GetChildrenAllValid(token, value, depth))
            {
                List <int> invalidIndexes = new List <int>();
                int        index          = 0;
                foreach (SchemaScope schemaScope in ChildScopes)
                {
                    if (!schemaScope.IsValid)
                    {
                        invalidIndexes.Add(index);
                    }
                    else
                    {
                        ConditionalContext.TrackEvaluatedSchema(schemaScope.Schema);
                    }

                    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);
            }
            else
            {
                for (int i = 0; i < ChildScopes.Count; i++)
                {
                    ConditionalContext.TrackEvaluatedSchema(ChildScopes[i].Schema);
                }
            }

            return(true);
        }
        public void Initialize(ContextBase context, SchemaScope parent, int initialDepth, ScopeType type)
        {
            base.Initialize(context, parent, initialDepth, type);

            ParentSchemaScope = parent;
            ConditionalContext = ConditionalContext.Create(context);
        }
        protected override bool EvaluateTokenCore(JsonToken token, object value, int depth)
        {
            SchemaScope ifScope = GetSchemaScopeBySchema(If, token, value, depth);

            if (ifScope.IsValid)
            {
                if (Then != null)
                {
                    SchemaScope thenScope = GetSchemaScopeBySchema(Then, token, value, depth);

                    if (!thenScope.IsValid)
                    {
                        ConditionalContext context = (ConditionalContext)thenScope.Context;
                        RaiseError($"JSON does not match schema from 'then'.", ErrorType.Then, Then, null, context.Errors);
                    }
                }
            }
            else
            {
                if (Else != null)
                {
                    SchemaScope elseScope = GetSchemaScopeBySchema(Else, token, value, depth);

                    if (!elseScope.IsValid)
                    {
                        ConditionalContext context = (ConditionalContext)elseScope.Context;
                        RaiseError($"JSON does not match schema from 'else'.", ErrorType.Else, Else, null, context.Errors);
                    }
                }
            }

            return(true);
        }
Exemple #4
0
        public void Initialize(ContextBase context, SchemaScope parent, int initialDepth, ScopeType type)
        {
            base.Initialize(context, parent, initialDepth, type);

            ParentSchemaScope  = parent;
            ConditionalContext = ConditionalContext.Create(context);
        }
Exemple #5
0
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            if (TryGetChildrenAnyValid(token, value, depth, out bool anyValid))
            {
                if (!anyValid)
                {
                    RaiseError($"JSON does not match any schemas from 'anyOf'.", ErrorType.AnyOf, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                }

                // TODO: A little inefficent to find the valid children again
                foreach (SchemaScope childScope in ChildScopes)
                {
                    if (childScope.IsValid)
                    {
                        ConditionalContext.TrackEvaluatedSchema(childScope.Schema);
                    }
                }
            }
            else
            {
                RaiseCircularDependencyError(ErrorType.AnyOf);
            }

            return(true);
        }
        public override void Initialize(ContextBase context, SchemaScope parent, int initialDepth, ScopeType type)
        {
            base.Initialize(context, parent, initialDepth, type);

            ChildScopes.Clear();
            ParentSchemaScope  = parent;
            ConditionalContext = ConditionalContext.Create(context, parent.ShouldValidateUnevaluated());
        }
        public override void Initialize(ContextBase context, SchemaScope parent, int initialDepth, ScopeType type)
        {
            base.Initialize(context, parent, initialDepth, type);

            If   = null;
            Then = null;
            Else = null;

            ThenContext = null;
            ElseContext = null;
        }
Exemple #8
0
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            if (!TryGetSchemaScopeBySchema(If !, token, value, depth, out SchemaScope? ifScope))
            {
                RaiseCircularDependencyError(ErrorType.None);
                return(true);
            }

            if (ifScope.IsValid)
            {
                ConditionalContext.TrackEvaluatedSchema(ifScope.Schema);

                if (Then != null)
                {
                    if (!TryGetSchemaScopeBySchema(Then, token, value, depth, out SchemaScope? thenScope))
                    {
                        RaiseCircularDependencyError(ErrorType.Then);
                        return(true);
                    }

                    if (!thenScope.IsValid)
                    {
                        RaiseError($"JSON does not match schema from 'then'.", ErrorType.Then, Then, null, thenScope.GetValidationErrors());
                    }
                    else
                    {
                        ConditionalContext.TrackEvaluatedSchema(thenScope.Schema);
                    }
                }
            }
            else
            {
                if (Else != null)
                {
                    if (!TryGetSchemaScopeBySchema(Else, token, value, depth, out SchemaScope? elseScope))
                    {
                        RaiseCircularDependencyError(ErrorType.Else);
                        return(true);
                    }

                    if (!elseScope.IsValid)
                    {
                        RaiseError($"JSON does not match schema from 'else'.", ErrorType.Else, Else, null, elseScope.GetValidationErrors());
                    }
                    else
                    {
                        ConditionalContext.TrackEvaluatedSchema(elseScope.Schema);
                    }
                }
            }

            return(true);
        }
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            // If there is a recursive chain of $ref schemas then this will stack overflow.
            // If the ref scope is already evaluating then exit without checking children.
            if (_isReentrant)
            {
                return(true);
            }

            _isReentrant = true;
            try
            {
                if (TryGetChildrenAllValid(token, value, depth, out bool allValid))
                {
                    if (!allValid)
                    {
                        List <int> invalidIndexes = new List <int>();
                        int        index          = 0;
                        foreach (SchemaScope schemaScope in ChildScopes)
                        {
                            if (!schemaScope.IsValid)
                            {
                                invalidIndexes.Add(index);
                            }
                            else
                            {
                                ConditionalContext.TrackEvaluatedSchema(schemaScope.Schema);
                            }

                            index++;
                        }

                        IFormattable message = $"JSON does not match schema from '$ref'.";
                        RaiseError(message, ErrorType.Ref, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                    }
                    else
                    {
                        ConditionalContext.TrackEvaluatedSchema(ChildScopes[0].Schema);
                    }
                }
                else
                {
                    RaiseCircularDependencyError(ErrorType.Ref);
                }

                return(true);
            }
            finally
            {
                _isReentrant = false;
            }
        }
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            if (TryGetChildrenValidCount(token, value, depth, out int validCount))
            {
                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);
                }
                else
                {
                    // TODO: A little inefficent to find the valid child again
                    foreach (SchemaScope childScope in ChildScopes)
                    {
                        if (childScope.IsValid)
                        {
                            ConditionalContext.TrackEvaluatedSchema(childScope.Schema);
                        }
                    }
                }
            }
            else
            {
                RaiseCircularDependencyError(ErrorType.OneOf);
            }

            return(true);
        }
Exemple #11
0
        protected override bool EvaluateTokenCore(JsonToken token, object?value, int depth)
        {
            if (Parent is ObjectScope objectScope)
            {
                var readProperties = objectScope.ReadProperties;
                ValidationUtils.Assert(readProperties != null);
                ValidationUtils.Assert(PropertyName != null);

                if (readProperties.Contains(PropertyName))
                {
                    if (TryGetChildrenAnyValid(token, value, depth, out bool anyValid))
                    {
                        if (!anyValid)
                        {
                            RaiseError($"Dependencies for property '{PropertyName}' failed.", ErrorType.Dependencies, ParentSchemaScope.Schema, null, ConditionalContext.Errors);
                        }
                        else
                        {
                            foreach (SchemaScope childScope in ChildScopes)
                            {
                                if (childScope.IsValid)
                                {
                                    ConditionalContext.TrackEvaluatedSchema(childScope.Schema);
                                }
                            }
                        }
                    }
                    else
                    {
                        RaiseCircularDependencyError(ErrorType.Dependencies);
                    }
                }
            }

            return(true);
        }
Exemple #12
0
        public static SchemaScope CreateTokenScope(JsonToken token, JSchema schema, ContextBase context, SchemaScope parent, int depth)
        {
            SchemaScope scope;

            switch (token)
            {
            case JsonToken.StartObject:
                ObjectScope objectScope = context.Validator.GetCachedScope <ObjectScope>(ScopeType.Object);
                if (objectScope == null)
                {
                    objectScope = new ObjectScope();
                }
                objectScope.Initialize(context, parent, depth, schema);
                context.Scopes.Add(objectScope);

                objectScope.InitializeScopes(token);

                scope = objectScope;
                break;

            case JsonToken.StartArray:
            case JsonToken.StartConstructor:
                ArrayScope arrayScope = context.Validator.GetCachedScope <ArrayScope>(ScopeType.Array);
                if (arrayScope == null)
                {
                    arrayScope = new ArrayScope();
                }
                arrayScope.Initialize(context, parent, depth, schema);

                context.Scopes.Add(arrayScope);
                scope = arrayScope;
                break;

            default:
                PrimativeScope primativeScope = context.Validator.GetCachedScope <PrimativeScope>(ScopeType.Primitive);
                if (primativeScope == null)
                {
                    primativeScope = new PrimativeScope();
                }
                primativeScope.Initialize(context, parent, depth, schema);

                scope = primativeScope;
                context.Scopes.Add(scope);
                break;
            }

            if (!schema._allOf.IsNullOrEmpty())
            {
                AllOfScope allOfScope = context.Validator.GetCachedScope <AllOfScope>(ScopeType.AllOf);
                if (allOfScope == null)
                {
                    allOfScope = new AllOfScope();
                }
                allOfScope.Initialize(context, scope, depth, ScopeType.AllOf);
                scope.AddChildScope(allOfScope);

                allOfScope.InitializeScopes(token, schema._allOf.GetInnerList(), context.Scopes.Count - 1);
            }
            if (!schema._anyOf.IsNullOrEmpty())
            {
                AnyOfScope anyOfScope = context.Validator.GetCachedScope <AnyOfScope>(ScopeType.AnyOf);
                if (anyOfScope == null)
                {
                    anyOfScope = new AnyOfScope();
                }
                anyOfScope.Initialize(context, scope, depth, ScopeType.AnyOf);
                scope.AddChildScope(anyOfScope);

                anyOfScope.InitializeScopes(token, schema._anyOf.GetInnerList(), context.Scopes.Count - 1);
            }
            if (!schema._oneOf.IsNullOrEmpty())
            {
                OneOfScope oneOfScope = context.Validator.GetCachedScope <OneOfScope>(ScopeType.OneOf);
                if (oneOfScope == null)
                {
                    oneOfScope = new OneOfScope();
                }
                oneOfScope.Initialize(context, scope, depth, ScopeType.OneOf);
                scope.AddChildScope(oneOfScope);

                oneOfScope.InitializeScopes(token, schema._oneOf.GetInnerList(), context.Scopes.Count - 1);
            }
            if (schema.Not != null)
            {
                NotScope notScope = context.Validator.GetCachedScope <NotScope>(ScopeType.Not);
                if (notScope == null)
                {
                    notScope = new NotScope();
                }
                notScope.Initialize(context, scope, depth, ScopeType.Not);
                scope.AddChildScope(notScope);

                notScope.InitializeScopes(token, new List <JSchema> {
                    schema.Not
                }, context.Scopes.Count - 1);
            }
            // only makes sense to eval if/then/else when there is an if and either a then or a else
            if (schema.If != null && (schema.Then != null || schema.Else != null))
            {
                IfThenElseScope ifThenElseScope = context.Validator.GetCachedScope <IfThenElseScope>(ScopeType.IfThenElse);
                if (ifThenElseScope == null)
                {
                    ifThenElseScope = new IfThenElseScope();
                }
                ifThenElseScope.Initialize(context, scope, depth, ScopeType.IfThenElse);
                scope.AddChildScope(ifThenElseScope);

                ifThenElseScope.If = schema.If;
                if (schema.Then != null)
                {
                    ifThenElseScope.Then        = schema.Then;
                    ifThenElseScope.ThenContext = ConditionalContext.Create(context);
                }
                if (schema.Else != null)
                {
                    ifThenElseScope.Else        = schema.Else;
                    ifThenElseScope.ElseContext = ConditionalContext.Create(context);
                }

                ifThenElseScope.InitializeScopes(token, context.Scopes.Count - 1);
            }

            return(scope);
        }
 public void InitializeScopes(JsonToken token)
 {
     if (!Schema._dependencies.IsNullOrEmpty())
     {
         foreach (KeyValuePair <string, object> dependency in Schema._dependencies.GetInnerDictionary())
         {
             JSchema dependencySchema = dependency.Value as JSchema;
             if (dependencySchema != null)
             {
                 SchemaScope scope = CreateTokenScope(token, dependencySchema, ConditionalContext.Create(Context), null, InitialDepth);
                 _dependencyScopes.Add(dependency.Key, scope);
             }
         }
     }
 }
 protected ConditionalScope(ContextBase context, SchemaScope parent, int initialDepth)
     : base(context, parent, initialDepth)
 {
     ParentSchemaScope  = parent;
     ConditionalContext = ConditionalContext.Create(context);
 }
 public ConditionalContext CreateConditionalContext()
 {
     return(ConditionalContext.Create(Context, ShouldValidateUnevaluated()));
 }
        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);
        }
        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);
        }
        private void InitializeScope(JsonToken token, int scopeIndex, JSchema schema, ConditionalContext context)
        {
            // cache this for performance
            int scopeCurrentIndex = scopeIndex;

            // check to see whether a scope with the same schema exists
            SchemaScope childScope = GetExistingSchemaScope(schema, ref scopeCurrentIndex);

            if (childScope == null)
            {
                childScope = SchemaScope.CreateTokenScope(token, schema, context, null, InitialDepth);
            }

#if DEBUG
            childScope.ConditionalParents.Add(this);
#endif

            ChildScopes.Add(childScope);
        }
Exemple #19
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
 protected ConditionalScope(ContextBase context, SchemaScope parent, int initialDepth)
     : base(context, parent, initialDepth)
 {
     ParentSchemaScope = parent;
     ConditionalContext = ConditionalContext.Create(context);
 }