From 0da15f6ffde92882ffe801b51dd8fa99f8a15288 Mon Sep 17 00:00:00 2001
From: GeWuYou <95328647+GeWuYou@users.noreply.github.com>
Date: Mon, 20 Apr 2026 14:30:11 +0800
Subject: [PATCH] =?UTF-8?q?fix(config):=20=E4=BF=AE=E5=A4=8D=E6=9D=A1?=
=?UTF-8?q?=E4=BB=B6=E5=88=86=E6=94=AF=E8=AF=8A=E6=96=AD=E4=B8=8E=E6=96=87?=
=?UTF-8?q?=E6=A1=A3=E6=91=98=E8=A6=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- 修复 then/else 非 object 分支诊断定位到具体条件路径
- 优化 if/then/else 文档摘要,补充 properties 内约束说明
- 补充生成器回归测试,覆盖分支路径与文档输出
---
.../Config/SchemaConfigGenerator.cs | 60 ++++++++++++++++--
.../Config/SchemaConfigGeneratorTests.cs | 62 ++++++++++++++++++-
2 files changed, 117 insertions(+), 5 deletions(-)
diff --git a/GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs b/GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs
index 92be27f5..0ca5ea00 100644
--- a/GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs
+++ b/GFramework.Game.SourceGenerators/Config/SchemaConfigGenerator.cs
@@ -1590,7 +1590,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
ConfigSchemaDiagnostics.InvalidConditionalSchemaMetadata,
CreateFileLocation(filePath),
Path.GetFileName(filePath),
- displayPath,
+ branchPath,
$"The '{keywordName}' value must be an object-valued schema.");
return false;
}
@@ -4214,7 +4214,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
return null;
}
- var ifSummary = TryBuildInlineSchemaSummary(ifElement, includeRequiredProperties: true);
+ var ifSummary = TryBuildConditionalBranchSummary(ifElement);
if (ifSummary is null)
{
return null;
@@ -4224,7 +4224,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
if (element.TryGetProperty("then", out var thenElement) &&
thenElement.ValueKind == JsonValueKind.Object)
{
- var thenSummary = TryBuildInlineSchemaSummary(thenElement, includeRequiredProperties: true);
+ var thenSummary = TryBuildConditionalBranchSummary(thenElement);
if (thenSummary is not null)
{
parts.Add($"then {thenSummary}");
@@ -4234,7 +4234,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
if (element.TryGetProperty("else", out var elseElement) &&
elseElement.ValueKind == JsonValueKind.Object)
{
- var elseSummary = TryBuildInlineSchemaSummary(elseElement, includeRequiredProperties: true);
+ var elseSummary = TryBuildConditionalBranchSummary(elseElement);
if (elseSummary is not null)
{
parts.Add($"else {elseSummary}");
@@ -4246,6 +4246,58 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
: null;
}
+ ///
+ /// 汇总条件分支的对象级约束与子属性约束,避免生成文档只保留笼统的 object 描述。
+ ///
+ /// 条件分支 schema。
+ /// 格式化后的条件分支摘要。
+ private static string? TryBuildConditionalBranchSummary(JsonElement branchElement)
+ {
+ var branchSummary = TryBuildInlineSchemaSummary(branchElement, includeRequiredProperties: true);
+ if (branchSummary is null)
+ {
+ return null;
+ }
+
+ var propertiesSummary = TryBuildInlineObjectPropertiesSummary(branchElement);
+ return propertiesSummary is null
+ ? branchSummary
+ : $"{branchSummary}; properties = {propertiesSummary}";
+ }
+
+ ///
+ /// 汇总对象 properties 内每个字段的紧凑约束,补足条件分支文档里的触发条件细节。
+ ///
+ /// 对象 schema 节点。
+ /// 格式化后的子属性约束摘要。
+ private static string? TryBuildInlineObjectPropertiesSummary(JsonElement schemaElement)
+ {
+ if (!schemaElement.TryGetProperty("properties", out var propertiesElement) ||
+ propertiesElement.ValueKind != JsonValueKind.Object)
+ {
+ return null;
+ }
+
+ var parts = new List();
+ foreach (var property in propertiesElement.EnumerateObject())
+ {
+ if (property.Value.ValueKind != JsonValueKind.Object)
+ {
+ continue;
+ }
+
+ var propertySummary = TryBuildInlineSchemaSummary(property.Value);
+ if (propertySummary is not null)
+ {
+ parts.Add($"{property.Name}: {propertySummary}");
+ }
+ }
+
+ return parts.Count == 0
+ ? null
+ : $"{{ {string.Join("; ", parts)} }}";
+ }
+
///
/// 将数组 contains 子 schema 整理成 XML 文档可读字符串。
/// 输出优先保持紧凑,只展示消费者在强类型 API 上最需要看到的匹配摘要。
diff --git a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
index 77b12495..dae574a3 100644
--- a/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
+++ b/GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
@@ -1338,7 +1338,10 @@ public class SchemaConfigGeneratorTests
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
Assert.That(
generatedSources["MonsterConfig.g.cs"],
- Does.Contain("Constraints: if/then/else = if object; then object (required = [itemCount]); else object (required = [bonus])."));
+ Does.Contain(
+ "Constraints: if/then/else = if object; properties = { itemId: string (const = \"potion\") }; " +
+ "then object (required = [itemCount]); properties = { itemCount: integer }; " +
+ "else object (required = [bonus]); properties = { bonus: integer }."));
}
///
@@ -1394,6 +1397,63 @@ public class SchemaConfigGeneratorTests
});
}
+ ///
+ /// 验证条件分支不是 object schema 时,诊断路径会定位到具体分支而不是父对象。
+ ///
+ [Test]
+ public void Run_Should_Report_Diagnostic_With_Branch_Path_When_Then_Schema_Is_Not_Object()
+ {
+ const string source = """
+ namespace TestApp
+ {
+ public sealed class Dummy
+ {
+ }
+ }
+ """;
+
+ const string schema = """
+ {
+ "type": "object",
+ "required": ["id", "reward"],
+ "properties": {
+ "id": { "type": "integer" },
+ "reward": {
+ "type": "object",
+ "properties": {
+ "itemId": { "type": "string" },
+ "itemCount": { "type": "integer" }
+ },
+ "if": {
+ "type": "object",
+ "properties": {
+ "itemId": {
+ "type": "string",
+ "const": "potion"
+ }
+ }
+ },
+ "then": []
+ }
+ }
+ }
+ """;
+
+ var result = SchemaGeneratorTestDriver.Run(
+ source,
+ ("monster.schema.json", schema));
+
+ var diagnostic = result.Results.Single().Diagnostics.Single();
+
+ Assert.Multiple(() =>
+ {
+ Assert.That(diagnostic.Id, Is.EqualTo("GF_ConfigSchema_013"));
+ Assert.That(diagnostic.Severity, Is.EqualTo(DiagnosticSeverity.Error));
+ Assert.That(diagnostic.GetMessage(), Does.Contain("reward[then]"));
+ Assert.That(diagnostic.GetMessage(), Does.Contain("must be an object-valued schema"));
+ });
+ }
+
///
/// 验证条件分支不能引用父对象未声明的字段。
///