public SchemaScope(JTokenType tokenType, JsonSchemaModel schema) { _tokenType = tokenType; _schema = schema; if (_schema != null && _schema.Properties != null) _requiredProperties = GetRequiredProperties(_schema).Distinct().ToDictionary(p => p, p => false); else _requiredProperties = new Dictionary<string, bool>(); }
private IEnumerable<string> GetRequiredProperties(JsonSchemaModel schema) { return schema.Properties.Where(p => !p.Value.Optional).Select(p => p.Key); }
private void ValidatePropertyName(JsonSchemaModel schema) { if (schema == null) return; string propertyName = Convert.ToString(_reader.Value, CultureInfo.InvariantCulture); if (_currentScope.RequiredProperties.ContainsKey(propertyName)) _currentScope.RequiredProperties[propertyName] = true; if (schema.Properties != null && !schema.Properties.ContainsKey(propertyName)) { IList<string> definedProperties = schema.Properties.Select(p => p.Key).ToList(); if (!schema.AllowAdditionalProperties && !definedProperties.Contains(propertyName)) { RaiseError("Property '{0}' has not been defined and the schema does not allow additional properties.".FormatWith(CultureInfo.InvariantCulture, propertyName), schema); } } _currentScope.CurrentPropertyName = propertyName; }
private void ValidateString(JsonSchemaModel schema) { if (schema == null) return; if (!TestType(schema, JsonSchemaType.String)) return; ValidateInEnumAndNotDisallowed(schema); string value = _reader.Value.ToString(); if (schema.MaximumLength != null && value.Length > schema.MaximumLength) RaiseError("String '{0}' exceeds maximum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MaximumLength), schema); if (schema.MinimumLength != null && value.Length < schema.MinimumLength) RaiseError("String '{0}' is less than minimum length of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.MinimumLength), schema); if (schema.Patterns != null) { foreach (string pattern in schema.Patterns) { if (!Regex.IsMatch(value, pattern)) RaiseError("String '{0}' does not match regex pattern '{1}'.".FormatWith(CultureInfo.InvariantCulture, value, pattern), schema); } } }
private void ValidateNull(JsonSchemaModel schema) { if (schema == null) return; if (!TestType(schema, JsonSchemaType.Null)) return; ValidateInEnumAndNotDisallowed(schema); }
private bool ValidateObject(JsonSchemaModel schema) { if (schema == null) return true; return (TestType(schema, JsonSchemaType.Object)); }
private void ValidateInEnumAndNotDisallowed(JsonSchemaModel schema) { if (schema == null) return; JToken value = new JValue(_reader.Value); if (schema.Enum != null) { if (!schema.Enum.ContainsValue(value, new JTokenEqualityComparer())) RaiseError("Value {0} is not defined in enum.".FormatWith(CultureInfo.InvariantCulture, value), schema); } JsonSchemaType? currentNodeType = GetCurrentNodeSchemaType(); if (currentNodeType != null) { if (JsonSchemaGenerator.HasFlag(schema.Disallow, currentNodeType.Value)) RaiseError("Type {0} is disallowed.".FormatWith(CultureInfo.InvariantCulture, currentNodeType), schema); } }
private bool TestType(JsonSchemaModel currentSchema, JsonSchemaType currentType) { if (!JsonSchemaGenerator.HasFlag(currentSchema.Type, currentType)) { RaiseError("Invalid type. Expected {0} but got {1}.".FormatWith(CultureInfo.InvariantCulture, currentSchema.Type, currentType), currentSchema); return false; } return true; }
private void ValidateEndObject(JsonSchemaModel schema) { if (schema == null) return; Dictionary<string, bool> requiredProperties = _currentScope.RequiredProperties; if (requiredProperties != null) { List<string> unmatchedRequiredProperties = requiredProperties.Where(kv => !kv.Value).Select(kv => kv.Key).ToList(); if (unmatchedRequiredProperties.Count > 0) RaiseError("Non-optional properties are missing from object: {0}.".FormatWith(CultureInfo.InvariantCulture, string.Join(", ", unmatchedRequiredProperties.ToArray())), schema); } }
private void ValidateFloat(JsonSchemaModel schema) { if (schema == null) return; if (!TestType(schema, JsonSchemaType.Float)) return; ValidateInEnumAndNotDisallowed(schema); double value = Convert.ToDouble(_reader.Value, CultureInfo.InvariantCulture); if (schema.Maximum != null && value > schema.Maximum) RaiseError("Float {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Maximum), schema); if (schema.Minimum != null && value < schema.Minimum) RaiseError("Float {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.Minimum), schema); if (schema.MaximumDecimals != null && MathUtils.GetDecimalPlaces(value) > schema.MaximumDecimals) RaiseError("Float {0} exceeds the maximum allowed number decimal places of {1}.".FormatWith(CultureInfo.InvariantCulture, JsonConvert.ToString(value), schema.MaximumDecimals), schema); }
private void ValidateEndArray(JsonSchemaModel schema) { if (schema == null) return; int arrayItemCount = _currentScope.ArrayItemCount; if (schema.MaximumItems != null && arrayItemCount > schema.MaximumItems) RaiseError("Array item count {0} exceeds maximum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MaximumItems), schema); if (schema.MinimumItems != null && arrayItemCount < schema.MinimumItems) RaiseError("Array item count {0} is less than minimum count of {1}.".FormatWith(CultureInfo.InvariantCulture, arrayItemCount, schema.MinimumItems), schema); }
private void ValidateCurrentToken() { // first time validate has been called. build model if (_model == null) { JsonSchemaModelBuilder builder = new JsonSchemaModelBuilder(); _model = builder.Build(_schema); } switch (_reader.TokenType) { case JsonToken.StartObject: ProcessValue(); JsonSchemaModel objectSchema = (ValidateObject(CurrentMemberSchema)) ? CurrentMemberSchema : null; Push(new SchemaScope(JTokenType.Object, objectSchema)); break; case JsonToken.StartArray: ProcessValue(); JsonSchemaModel arraySchema = (ValidateArray(CurrentMemberSchema)) ? CurrentMemberSchema : null; Push(new SchemaScope(JTokenType.Array, arraySchema)); break; case JsonToken.StartConstructor: Push(new SchemaScope(JTokenType.Constructor, null)); break; case JsonToken.PropertyName: ValidatePropertyName(CurrentSchema); break; case JsonToken.Raw: break; case JsonToken.Integer: ProcessValue(); ValidateInteger(CurrentMemberSchema); break; case JsonToken.Float: ProcessValue(); ValidateFloat(CurrentMemberSchema); break; case JsonToken.String: ProcessValue(); ValidateString(CurrentMemberSchema); break; case JsonToken.Boolean: ProcessValue(); ValidateBoolean(CurrentMemberSchema); break; case JsonToken.Null: ProcessValue(); ValidateNull(CurrentMemberSchema); break; case JsonToken.Undefined: break; case JsonToken.EndObject: ValidateEndObject(CurrentSchema); Pop(); break; case JsonToken.EndArray: ValidateEndArray(CurrentSchema); Pop(); break; case JsonToken.EndConstructor: Pop(); break; case JsonToken.Date: break; default: throw new ArgumentOutOfRangeException(); } }
private bool ValidateArray(JsonSchemaModel schema) { if (schema == null) return true; return (TestType(schema, JsonSchemaType.Array)); }
public static JsonSchemaModel Create(IList<JsonSchema> schemata) { JsonSchemaModel model = new JsonSchemaModel(); foreach (JsonSchema schema in schemata) { Combine(model, schema); } return model; }
private void ValidateInteger(JsonSchemaModel schema) { if (schema == null) return; if (!TestType(schema, JsonSchemaType.Integer)) return; ValidateInEnumAndNotDisallowed(schema); long value = Convert.ToInt64(_reader.Value, CultureInfo.InvariantCulture); if (schema.Maximum != null && value > schema.Maximum) RaiseError("Integer {0} exceeds maximum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Maximum), schema); if (schema.Minimum != null && value < schema.Minimum) RaiseError("Integer {0} is less than minimum value of {1}.".FormatWith(CultureInfo.InvariantCulture, value, schema.Minimum), schema); }
private static void Combine(JsonSchemaModel model, JsonSchema schema) { model.Optional = model.Optional && (schema.Optional ?? false); model.Type = model.Type & (schema.Type ?? JsonSchemaType.Any); model.MinimumLength = MathUtils.Max(model.MinimumLength, schema.MinimumLength); model.MaximumLength = MathUtils.Min(model.MaximumLength, schema.MaximumLength); model.MaximumDecimals = MathUtils.Min(model.MaximumDecimals, schema.MaximumDecimals); model.Minimum = MathUtils.Max(model.Minimum, schema.Minimum); model.Maximum = MathUtils.Max(model.Maximum, schema.Maximum); model.MinimumItems = MathUtils.Max(model.MinimumItems, schema.MinimumItems); model.MaximumItems = MathUtils.Min(model.MaximumItems, schema.MaximumItems); model.AllowAdditionalProperties = model.AllowAdditionalProperties && schema.AllowAdditionalProperties; if (schema.Enum != null) { if (model.Enum == null) model.Enum = new List<JToken>(); model.Enum.AddRangeDistinct(schema.Enum, new JTokenEqualityComparer()); } model.Disallow = model.Disallow | (schema.Disallow ?? JsonSchemaType.None); if (schema.Pattern != null) { if (model.Patterns == null) model.Patterns = new List<string>(); model.Patterns.AddDistinct(schema.Pattern); } }
private void RaiseError(string message, JsonSchemaModel schema) { IJsonLineInfo lineInfo = this; string exceptionMessage = (lineInfo.HasLineInfo()) ? message + " Line {0}, position {1}.".FormatWith(CultureInfo.InvariantCulture, lineInfo.LineNumber, lineInfo.LinePosition) : message; OnValidationEvent(new JsonSchemaException(exceptionMessage, null, lineInfo.LineNumber, lineInfo.LinePosition)); }