private void ValidateNumber <T>(JToken node, ICollection <string> errorMessages) where T : KongObject
        {
            var number = (double)node;

            if (OneOf.Any())
            {
                var options = OneOf.Select(x => x.Value <double>()).ToArray();
                if (!options.Contains(number))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should be one of '{string.Join(", ", options)}').");
                }
            }
            if (Between != null)
            {
                if (number < Between[0] || number > Between[1])
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should be between '{Between[0]}' and '{Between[1]}').");
                }
            }
            if (Gt.HasValue)
            {
                if (number <= Gt.Value)
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should be greater than '{Gt.Value}').");
                }
            }
        }
        /// <summary>
        /// Converts an object to a <see cref="JsonValue"/>.
        /// </summary>
        /// <param name="serializer">The <see cref="JsonSerializer"/> instance to use for additional serialization of values.</param>
        /// <returns>The <see cref="JsonValue"/> representation of the object.</returns>
        public virtual JsonValue ToJson(JsonSerializer serializer)
        {
            var json = new JsonObject();

            if (Id != null)
            {
                json["id"] = Id;
            }
            if (!string.IsNullOrWhiteSpace(Schema))
            {
                json["$schema"] = Schema;
            }
            if (Title != null)
            {
                json["title"] = Title;
            }
            if (!string.IsNullOrWhiteSpace(Description))
            {
                json["description"] = Description;
            }
            if (Default != null)
            {
                json["default"] = Default;
            }
            if (MultipleOf.HasValue)
            {
                json["multipleOf"] = MultipleOf;
            }
            if (Maximum.HasValue)
            {
                json["maximum"] = Maximum;
            }
            if (ExclusiveMaximum.HasValue)
            {
                json["exclusiveMaximum"] = ExclusiveMaximum;
            }
            if (Minimum.HasValue)
            {
                json["minimum"] = Minimum;
            }
            if (ExclusiveMinimum.HasValue)
            {
                json["exclusiveMinimum"] = ExclusiveMinimum;
            }
            if (MaxLength.HasValue)
            {
                json["maxLength"] = MaxLength;
            }
            if (MinLength.HasValue)
            {
                json["minLength"] = MinLength;
            }
            if (Pattern != null)
            {
                json["pattern"] = Pattern;
            }
            if (AdditionalItems != null)
            {
                json["additionalItems"] = AdditionalItems.ToJson(serializer);
            }
            if (Items != null)
            {
                json["items"] = Items.ToJson(serializer);
            }
            if (MaxItems.HasValue)
            {
                json["maxItems"] = MinItems;
            }
            if (MinItems.HasValue)
            {
                json["minItems"] = MinItems;
            }
            if (UniqueItems ?? false)
            {
                json["uniqueItems"] = UniqueItems;
            }
            if (MaxProperties.HasValue)
            {
                json["maxProperties"] = MaxProperties;
            }
            if (MinProperties.HasValue)
            {
                json["minProperties"] = MinProperties;
            }
            if (Required != null)
            {
                var array = Required.ToJson();
                array.Array.EqualityStandard = ArrayEquality.ContentsEqual;
                json["required"]             = array;
            }
            if (AdditionalProperties != null)
            {
                json["additionalProperties"] = AdditionalProperties.ToJson(serializer);
            }
            if (Definitions != null)
            {
                json["definitions"] = Definitions.ToJson(serializer);
            }
            if (Properties != null)
            {
                json["properties"] = Properties.ToJson(serializer);
            }
            if (PatternProperties != null && PatternProperties.Any())
            {
                json["patternProperties"] = PatternProperties.ToDictionary(kvp => kvp.Key.ToString(), kvp => kvp.Value).ToJson(serializer);
            }
            if (Dependencies != null && Dependencies.Any())
            {
                var jsonDependencies = new JsonObject();
                foreach (var dependency in Dependencies)
                {
                    jsonDependencies[dependency.PropertyName] = dependency.GetJsonData();
                }
                json["dependencies"] = jsonDependencies;
            }
            if (Enum != null)
            {
                var array = Enum.ToJson(serializer);
                array.Array.EqualityStandard = ArrayEquality.ContentsEqual;
                json["enum"] = Enum.ToJson(serializer);
            }
            if (Type != JsonSchemaType.NotDefined)
            {
                var array = Type.ToJson();
                if (array.Type == JsonValueType.Array)
                {
                    array.Array.EqualityStandard = ArrayEquality.ContentsEqual;
                }
                json["type"] = array;
            }
            if (AllOf != null)
            {
                var array = AllOf.Select(s => s.ToJson(serializer)).ToJson();
                array.EqualityStandard = ArrayEquality.ContentsEqual;
                json["allOf"]          = array;
            }
            if (AnyOf != null)
            {
                var array = AnyOf.Select(s => s.ToJson(serializer)).ToJson();
                array.EqualityStandard = ArrayEquality.ContentsEqual;
                json["anyOf"]          = array;
            }
            if (OneOf != null)
            {
                var array = OneOf.Select(s => s.ToJson(serializer)).ToJson();
                array.EqualityStandard = ArrayEquality.ContentsEqual;
                json["oneOf"]          = array;
            }
            if (Not != null)
            {
                json["not"] = Not.ToJson(serializer);
            }
            if (Format != null)
            {
                json["format"] = Format.Key;
            }
            if (ExtraneousDetails != null)
            {
                foreach (var kvp in ExtraneousDetails.Where(kvp => !_definedProperties.Contains(kvp.Key)))
                {
                    json[kvp.Key] = kvp.Value;
                }
            }
            return(json);
        }
        private void ValidateString <T>(JToken node, ICollection <string> errorMessages) where T : KongObject
        {
            var value = (string)node;

            if (OneOf.Any())
            {
                var options = OneOf.Select(x => x.Value <string>()).ToArray();
                if (!options.Contains(value))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should be one of '{string.Join(", ", options)}').");
                }
            }
            if (StartsWith != null)
            {
                if (value == null || !value.StartsWith(StartsWith))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should start with '{StartsWith}').");
                }
            }
            if (Match != null)
            {
                if (!LuaPattern.IsMatch(value, Match))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should match lua pattern '{Match}').");
                }
            }
            if (MatchAny != null)
            {
                if (MatchAny.Patterns.All(x => !LuaPattern.IsMatch(value, x)))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' {MatchAny.Error}).");
                }
            }
            if (MatchNone.Any())
            {
                foreach (var fieldCheck in MatchNone)
                {
                    if (LuaPattern.IsMatch(value, fieldCheck.Pattern))
                    {
                        errorMessages.Add($"{Violation<T>()} (field '{node.Path}' {fieldCheck.Error}).");
                    }
                }
            }
            if (MatchAll.Any())
            {
                foreach (var fieldCheck in MatchAll)
                {
                    if (!LuaPattern.IsMatch(value, fieldCheck.Pattern))
                    {
                        errorMessages.Add($"{Violation<T>()} (field '{node.Path}' {fieldCheck.Error}).");
                    }
                }
            }
            if (LenMin.HasValue)
            {
                var len = value?.Length;
                if (len < LenMin)
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should have min length '{LenMin.Value}').");
                }
            }
            if (Uuid)
            {
                if (!Guid.TryParse(value, out _))
                {
                    errorMessages.Add($"{Violation<T>()} (field '{node.Path}' should be a 'uuid').");
                }
            }
        }