mirror of
https://github.com/GeWuYou/GFramework.git
synced 2026-05-12 22:03:30 +08:00
fix(config): 修复条件分支诊断与文档摘要
- 修复 then/else 非 object 分支诊断定位到具体条件路径 - 优化 if/then/else 文档摘要,补充 properties 内约束说明 - 补充生成器回归测试,覆盖分支路径与文档输出
This commit is contained in:
parent
68d653623a
commit
0da15f6ffd
@ -1590,7 +1590,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
|||||||
ConfigSchemaDiagnostics.InvalidConditionalSchemaMetadata,
|
ConfigSchemaDiagnostics.InvalidConditionalSchemaMetadata,
|
||||||
CreateFileLocation(filePath),
|
CreateFileLocation(filePath),
|
||||||
Path.GetFileName(filePath),
|
Path.GetFileName(filePath),
|
||||||
displayPath,
|
branchPath,
|
||||||
$"The '{keywordName}' value must be an object-valued schema.");
|
$"The '{keywordName}' value must be an object-valued schema.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -4214,7 +4214,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var ifSummary = TryBuildInlineSchemaSummary(ifElement, includeRequiredProperties: true);
|
var ifSummary = TryBuildConditionalBranchSummary(ifElement);
|
||||||
if (ifSummary is null)
|
if (ifSummary is null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
@ -4224,7 +4224,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
|||||||
if (element.TryGetProperty("then", out var thenElement) &&
|
if (element.TryGetProperty("then", out var thenElement) &&
|
||||||
thenElement.ValueKind == JsonValueKind.Object)
|
thenElement.ValueKind == JsonValueKind.Object)
|
||||||
{
|
{
|
||||||
var thenSummary = TryBuildInlineSchemaSummary(thenElement, includeRequiredProperties: true);
|
var thenSummary = TryBuildConditionalBranchSummary(thenElement);
|
||||||
if (thenSummary is not null)
|
if (thenSummary is not null)
|
||||||
{
|
{
|
||||||
parts.Add($"then {thenSummary}");
|
parts.Add($"then {thenSummary}");
|
||||||
@ -4234,7 +4234,7 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
|||||||
if (element.TryGetProperty("else", out var elseElement) &&
|
if (element.TryGetProperty("else", out var elseElement) &&
|
||||||
elseElement.ValueKind == JsonValueKind.Object)
|
elseElement.ValueKind == JsonValueKind.Object)
|
||||||
{
|
{
|
||||||
var elseSummary = TryBuildInlineSchemaSummary(elseElement, includeRequiredProperties: true);
|
var elseSummary = TryBuildConditionalBranchSummary(elseElement);
|
||||||
if (elseSummary is not null)
|
if (elseSummary is not null)
|
||||||
{
|
{
|
||||||
parts.Add($"else {elseSummary}");
|
parts.Add($"else {elseSummary}");
|
||||||
@ -4246,6 +4246,58 @@ public sealed class SchemaConfigGenerator : IIncrementalGenerator
|
|||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 汇总条件分支的对象级约束与子属性约束,避免生成文档只保留笼统的 object 描述。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="branchElement">条件分支 schema。</param>
|
||||||
|
/// <returns>格式化后的条件分支摘要。</returns>
|
||||||
|
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}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 汇总对象 <c>properties</c> 内每个字段的紧凑约束,补足条件分支文档里的触发条件细节。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="schemaElement">对象 schema 节点。</param>
|
||||||
|
/// <returns>格式化后的子属性约束摘要。</returns>
|
||||||
|
private static string? TryBuildInlineObjectPropertiesSummary(JsonElement schemaElement)
|
||||||
|
{
|
||||||
|
if (!schemaElement.TryGetProperty("properties", out var propertiesElement) ||
|
||||||
|
propertiesElement.ValueKind != JsonValueKind.Object)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var parts = new List<string>();
|
||||||
|
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)} }}";
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 将数组 <c>contains</c> 子 schema 整理成 XML 文档可读字符串。
|
/// 将数组 <c>contains</c> 子 schema 整理成 XML 文档可读字符串。
|
||||||
/// 输出优先保持紧凑,只展示消费者在强类型 API 上最需要看到的匹配摘要。
|
/// 输出优先保持紧凑,只展示消费者在强类型 API 上最需要看到的匹配摘要。
|
||||||
|
|||||||
@ -1338,7 +1338,10 @@ public class SchemaConfigGeneratorTests
|
|||||||
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
Assert.That(result.Results.Single().Diagnostics, Is.Empty);
|
||||||
Assert.That(
|
Assert.That(
|
||||||
generatedSources["MonsterConfig.g.cs"],
|
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 }."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -1394,6 +1397,63 @@ public class SchemaConfigGeneratorTests
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证条件分支不是 object schema 时,诊断路径会定位到具体分支而不是父对象。
|
||||||
|
/// </summary>
|
||||||
|
[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"));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证条件分支不能引用父对象未声明的字段。
|
/// 验证条件分支不能引用父对象未声明的字段。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user