// Copyright (c) 2025-2026 GeWuYou
// SPDX-License-Identifier: Apache-2.0
namespace GFramework.Game.Config;
///
/// 表示单个 schema 节点的最小运行时描述。
/// 同一个模型同时覆盖对象、数组和标量,便于递归校验逻辑只依赖一种树结构。
///
internal sealed class YamlConfigSchemaNode
{
private readonly NodeChildren _children;
private readonly NodeValidation _validation;
private YamlConfigSchemaNode(
YamlConfigSchemaPropertyType nodeType,
NodeChildren children,
NodeValidation validation,
string schemaPathHint)
{
ArgumentNullException.ThrowIfNull(children);
ArgumentNullException.ThrowIfNull(validation);
ArgumentNullException.ThrowIfNull(schemaPathHint);
_children = children;
_validation = validation;
NodeType = nodeType;
Properties = children.Properties;
RequiredProperties = children.RequiredProperties;
ItemNode = children.ItemNode;
ReferenceTableName = validation.ReferenceTableName;
AllowedValues = validation.AllowedValues;
Constraints = validation.Constraints;
ArrayConstraints = validation.ArrayConstraints;
ObjectConstraints = validation.ObjectConstraints;
ConstantValue = validation.ConstantValue;
NegatedSchemaNode = validation.NegatedSchemaNode;
SchemaPathHint = schemaPathHint;
}
///
/// 获取节点类型。
///
public YamlConfigSchemaPropertyType NodeType { get; }
///
/// 获取对象属性集合;非对象节点时返回空。
///
public IReadOnlyDictionary? Properties { get; }
///
/// 获取对象必填属性集合;非对象节点时返回空。
///
public IReadOnlyCollection? RequiredProperties { get; }
///
/// 获取数组元素节点;非数组节点时返回空。
///
public YamlConfigSchemaNode? ItemNode { get; }
///
/// 获取目标引用表名称;未声明跨表引用时返回空。
///
public string? ReferenceTableName { get; }
///
/// 获取节点允许值集合;未声明 enum 时返回空。
///
public IReadOnlyCollection? AllowedValues { get; }
///
/// 获取标量范围与长度约束;未声明时返回空。
///
public YamlConfigScalarConstraints? Constraints { get; }
///
/// 获取对象属性数量约束;未声明时返回空。
///
public YamlConfigObjectConstraints? ObjectConstraints { get; }
///
/// 获取数组元素数量约束;未声明时返回空。
///
public YamlConfigArrayConstraints? ArrayConstraints { get; }
///
/// 获取节点常量约束;未声明 const 时返回空。
///
public YamlConfigConstantValue? ConstantValue { get; }
///
/// 获取节点声明的 not 子 schema;未声明时返回空。
///
public YamlConfigSchemaNode? NegatedSchemaNode { get; }
///
/// 获取用于诊断显示的 schema 路径提示。
/// 当前节点本身不记录独立路径,因此对象校验会回退到所属根 schema 路径。
///
public string SchemaPathHint { get; }
///
/// 创建对象节点描述。
///
/// 对象属性集合。
/// 对象必填属性集合。
/// 对象属性数量约束。
/// 用于错误信息的 schema 文件路径提示。
/// 对象节点模型。
public static YamlConfigSchemaNode CreateObject(
IReadOnlyDictionary? properties,
IReadOnlyCollection? requiredProperties,
YamlConfigObjectConstraints? objectConstraints,
string schemaPathHint)
{
return new YamlConfigSchemaNode(
YamlConfigSchemaPropertyType.Object,
new NodeChildren(properties, requiredProperties, itemNode: null),
new NodeValidation(
referenceTableName: null,
allowedValues: null,
constraints: null,
arrayConstraints: null,
objectConstraints,
constantValue: null,
negatedSchemaNode: null),
schemaPathHint);
}
///
/// 创建数组节点描述。
///
/// 数组元素节点。
/// 数组节点允许值集合。
/// 数组元素数量约束。
/// 用于错误信息的 schema 文件路径提示。
/// 数组节点模型。
public static YamlConfigSchemaNode CreateArray(
YamlConfigSchemaNode itemNode,
IReadOnlyCollection? allowedValues,
YamlConfigArrayConstraints? arrayConstraints,
string schemaPathHint)
{
return new YamlConfigSchemaNode(
YamlConfigSchemaPropertyType.Array,
new NodeChildren(properties: null, requiredProperties: null, itemNode),
new NodeValidation(
referenceTableName: null,
allowedValues,
constraints: null,
arrayConstraints,
objectConstraints: null,
constantValue: null,
negatedSchemaNode: null),
schemaPathHint);
}
///
/// 创建标量节点描述。
///
/// 标量节点类型。
/// 目标引用表名称。
/// 标量允许值集合。
/// 标量范围与长度约束。
/// 用于错误信息的 schema 文件路径提示。
/// 标量节点模型。
public static YamlConfigSchemaNode CreateScalar(
YamlConfigSchemaPropertyType nodeType,
string? referenceTableName,
IReadOnlyCollection? allowedValues,
YamlConfigScalarConstraints? constraints,
string schemaPathHint)
{
return new YamlConfigSchemaNode(
nodeType,
NodeChildren.None,
new NodeValidation(
referenceTableName,
allowedValues,
constraints,
arrayConstraints: null,
objectConstraints: null,
constantValue: null,
negatedSchemaNode: null),
schemaPathHint);
}
///
/// 基于当前节点复制一个只替换引用表名称的新节点。
/// 该方法用于把数组级别的 ref-table 语义挂接到元素节点上。
///
/// 新的目标引用表名称。
/// 复制后的节点。
public YamlConfigSchemaNode WithReferenceTable(string referenceTableName)
{
return new YamlConfigSchemaNode(
NodeType,
_children,
_validation.WithReferenceTable(referenceTableName),
SchemaPathHint);
}
///
/// 基于当前节点复制一个只替换 enum 允许值集合的新节点。
///
/// 新的允许值集合。
/// 复制后的节点。
public YamlConfigSchemaNode WithAllowedValues(IReadOnlyCollection? allowedValues)
{
return new YamlConfigSchemaNode(
NodeType,
_children,
_validation.WithAllowedValues(allowedValues),
SchemaPathHint);
}
///
/// 基于当前节点复制一个只替换常量约束的新节点。
///
/// 新的常量约束。
/// 复制后的节点。
public YamlConfigSchemaNode WithConstantValue(YamlConfigConstantValue? constantValue)
{
return new YamlConfigSchemaNode(
NodeType,
_children,
_validation.WithConstantValue(constantValue),
SchemaPathHint);
}
///
/// 基于当前节点复制一个只替换 not 子 schema 的新节点。
///
/// 新的 negated schema。
/// 复制后的节点。
public YamlConfigSchemaNode WithNegatedSchemaNode(YamlConfigSchemaNode? negatedSchemaNode)
{
return new YamlConfigSchemaNode(
NodeType,
_children,
_validation.WithNegatedSchemaNode(negatedSchemaNode),
SchemaPathHint);
}
private sealed class NodeChildren
{
public NodeChildren(
IReadOnlyDictionary? properties,
IReadOnlyCollection? requiredProperties,
YamlConfigSchemaNode? itemNode)
{
Properties = properties;
RequiredProperties = requiredProperties;
ItemNode = itemNode;
}
public static NodeChildren None { get; } = new(properties: null, requiredProperties: null, itemNode: null);
public IReadOnlyDictionary? Properties { get; }
public IReadOnlyCollection? RequiredProperties { get; }
public YamlConfigSchemaNode? ItemNode { get; }
}
private sealed class NodeValidation
{
public NodeValidation(
string? referenceTableName,
IReadOnlyCollection? allowedValues,
YamlConfigScalarConstraints? constraints,
YamlConfigArrayConstraints? arrayConstraints,
YamlConfigObjectConstraints? objectConstraints,
YamlConfigConstantValue? constantValue,
YamlConfigSchemaNode? negatedSchemaNode)
{
ReferenceTableName = referenceTableName;
AllowedValues = allowedValues;
Constraints = constraints;
ArrayConstraints = arrayConstraints;
ObjectConstraints = objectConstraints;
ConstantValue = constantValue;
NegatedSchemaNode = negatedSchemaNode;
}
public string? ReferenceTableName { get; }
public IReadOnlyCollection? AllowedValues { get; }
public YamlConfigScalarConstraints? Constraints { get; }
public YamlConfigArrayConstraints? ArrayConstraints { get; }
public YamlConfigObjectConstraints? ObjectConstraints { get; }
public YamlConfigConstantValue? ConstantValue { get; }
public YamlConfigSchemaNode? NegatedSchemaNode { get; }
public NodeValidation WithReferenceTable(string referenceTableName)
{
return new NodeValidation(referenceTableName, AllowedValues, Constraints, ArrayConstraints,
ObjectConstraints, ConstantValue, NegatedSchemaNode);
}
public NodeValidation WithAllowedValues(IReadOnlyCollection? allowedValues)
{
return new NodeValidation(ReferenceTableName, allowedValues, Constraints, ArrayConstraints,
ObjectConstraints, ConstantValue, NegatedSchemaNode);
}
public NodeValidation WithConstantValue(YamlConfigConstantValue? constantValue)
{
return new NodeValidation(ReferenceTableName, AllowedValues, Constraints, ArrayConstraints,
ObjectConstraints, constantValue, NegatedSchemaNode);
}
public NodeValidation WithNegatedSchemaNode(YamlConfigSchemaNode? negatedSchemaNode)
{
return new NodeValidation(ReferenceTableName, AllowedValues, Constraints, ArrayConstraints,
ObjectConstraints, ConstantValue, negatedSchemaNode);
}
}
}