Files
Pf2eDataScrapper/Pf2eDataScrapper/SchemaBuilder/TypeResolver.cs
T
2025-04-15 16:47:40 +04:00

112 lines
4.9 KiB
C#

using Newtonsoft.Json.Linq;
using Pf2eDataScrapper.SchemaBuilder.Types;
namespace Pf2eDataScrapper.SchemaBuilder;
/// <summary>
/// Класс для определения типа поля в схеме данных.
/// </summary>
internal class TypeResolver
{
/// <summary>
/// Проверка соответствия пути.
/// </summary>
/// <param name="node">Элемент, путь которого проверяется.</param>
/// <param name="path">Проверяемый путь. Допускается использование `*` в местах, где допускается любое значение.</param>
/// <returns>`true`, если `node.Path` соответсвует указанному в `path` значению.</returns>
public bool CheckPath(SchemaNode node, string path)
{
if (!path.Contains("*"))
{
return path == node.Path;
}
string[] pathParts = path.Split('.');
string[] nodeParts = node.Path.Split('.');
return pathParts.Length > nodeParts.Length ? false : !pathParts.Where((t, i) => t != "*" && t != nodeParts[i]).Any();
}
/// <summary>
/// Проверка соответствия пути.
/// </summary>
/// <param name="node">Элемент, путь которого проверяется.</param>
/// <param name="paths">Проверяемые пути. Допускается использование `*` в местах, где допускается любое значение.</param>
/// <returns>`true`, если `node.Path` соответсвует хотя бы одному указанному в `paths` значению.</returns>
public bool CheckPath(SchemaNode node, ICollection<string> paths)
{
return paths.Any(path => CheckPath(node, path));
}
/// <summary>
/// Получение типа значения.
/// </summary>
/// <param name="value">Значение.</param>
/// <returns>Типа значения.</returns>
public JTokenType TokenType(JToken? value)
{
return value is null || value.Type is JTokenType.Null or JTokenType.Undefined or JTokenType.None ? JTokenType.Null : value.Type;
}
/// <summary>
/// Частное определение типа поля.
/// </summary>
/// <param name="node">Поле схемы данных, для которого создаётся тип.</param>
/// <param name="value">Добавляемое значение.</param>
/// <returns>Новый тип для схемы данных. `null`, что бы использовать значение по умолчанию</returns>
protected virtual AbstractSchemaType? CustomResolve(SchemaNode node, JToken? value)
{
return null;
}
/// <summary>
/// Определение типа поля.
/// </summary>
/// <param name="node">Поле схемы данных, для которого создаётся тип.</param>
/// <param name="value">Добавляемое значение.</param>
/// <param name="disableResolve">Добавляемое значение.</param>
/// <returns>Новый тип для схемы данных</returns>
/// <exception cref="ArgumentNullException">
/// Возникает, если у `value` значение идентично `null`
/// (такие значения должны обрабаотываться в `SchemaNode`).
/// </exception>
public AbstractSchemaType Resolve(SchemaNode node, JToken? value, bool disableResolve)
{
if (!disableResolve)
{
AbstractSchemaType? customType = this.CustomResolve(node, value);
if (customType is not null)
{
return customType;
}
}
JTokenType type = TokenType(value);
return type == JTokenType.Null
? throw new ArgumentNullException(nameof(value))
: type switch
{
JTokenType.Array => new ArraySchemaType(node),
JTokenType.Object => new ObjectSchemaType(node),
_ => new StaticSchemaType(node, type)
};
}
/// <summary>
/// Определение типа поля.
/// </summary>
/// <param name="node">Поле схемы данных, для которого создаётся тип.</param>
/// <param name="value">Добавляемое значение.</param>
/// <returns>Новый тип для схемы данных</returns>
/// <exception cref="ArgumentNullException">
/// Возникает, если у `value` значение идентично `null`
/// (такие значения должны обрабаотываться в `SchemaNode`).
/// </exception>
public AbstractSchemaType Resolve(SchemaNode node, JToken? value)
{
return this.Resolve(node, value, false);
}
}