forked from aly/qstbak
126 lines
2.6 KiB
C#
126 lines
2.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Json.Schema;
|
|
|
|
namespace Questionable.Validation;
|
|
|
|
internal static class SchemaValidationHelper
|
|
{
|
|
internal readonly record struct ParsedError(string InstancePath, string PropertyPath, string Message);
|
|
|
|
public static void CollectLeafErrors(EvaluationResults node, List<ParsedError> errors)
|
|
{
|
|
if (!node.IsValid)
|
|
{
|
|
Dictionary<string, string> errors2 = node.Errors;
|
|
if (errors2 != null && errors2.Count > 0)
|
|
{
|
|
foreach (var (keyword, text3) in node.Errors)
|
|
{
|
|
if (!IsAggregateKeyword(keyword) && !string.IsNullOrWhiteSpace(text3))
|
|
{
|
|
string text4 = node.InstanceLocation.ToString();
|
|
string rawPath = GetRawPath(text4);
|
|
errors.Add(new ParsedError(text4 ?? string.Empty, FormatPath(rawPath), CleanMessage(text3)));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
List<EvaluationResults> details = node.Details;
|
|
if (details == null || details.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
foreach (EvaluationResults detail in node.Details)
|
|
{
|
|
if (!detail.IsValid)
|
|
{
|
|
CollectLeafErrors(detail, errors);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string FormatPath(string rawPath)
|
|
{
|
|
if (string.IsNullOrEmpty(rawPath))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
string[] array = rawPath.Split('/');
|
|
List<string> list = new List<string>();
|
|
string[] array2 = array;
|
|
foreach (string text in array2)
|
|
{
|
|
if (int.TryParse(text, out var result))
|
|
{
|
|
if (list.Count > 0)
|
|
{
|
|
list[list.Count - 1] += $"[{result}]";
|
|
}
|
|
else
|
|
{
|
|
list.Add($"[{result}]");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
list.Add(text);
|
|
}
|
|
}
|
|
return string.Join(".", list);
|
|
}
|
|
|
|
public static string CleanMessage(string message)
|
|
{
|
|
return message.Replace("\\u0022", "\"", StringComparison.Ordinal).Replace("\\u0027", "'", StringComparison.Ordinal);
|
|
}
|
|
|
|
public static string? FormatQuestLocation(byte? sequence, int? step)
|
|
{
|
|
if (!sequence.HasValue)
|
|
{
|
|
return null;
|
|
}
|
|
if (!step.HasValue)
|
|
{
|
|
return $"Seq {sequence}";
|
|
}
|
|
return $"Seq {sequence}, Step {step}";
|
|
}
|
|
|
|
private static bool IsAggregateKeyword(string keyword)
|
|
{
|
|
switch (keyword)
|
|
{
|
|
case "oneOf":
|
|
case "allOf":
|
|
case "anyOf":
|
|
case "else":
|
|
case "then":
|
|
case "if":
|
|
case "not":
|
|
case "prefixItems":
|
|
case "contains":
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private static string GetRawPath(string? instancePath)
|
|
{
|
|
if (string.IsNullOrEmpty(instancePath))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
if (instancePath.StartsWith('#'))
|
|
{
|
|
instancePath = instancePath.Substring(1);
|
|
}
|
|
if (instancePath.StartsWith('/'))
|
|
{
|
|
instancePath = instancePath.Substring(1);
|
|
}
|
|
return instancePath;
|
|
}
|
|
}
|