Skip to content

feat(config): 实现x-gframework-index索引元数据支持#195

Merged
GeWuYou merged 4 commits into
mainfrom
feat/game-config-system
Apr 8, 2026
Merged

feat(config): 实现x-gframework-index索引元数据支持#195
GeWuYou merged 4 commits into
mainfrom
feat/game-config-system

Conversation

@GeWuYou

@GeWuYou GeWuYou commented Apr 8, 2026

Copy link
Copy Markdown
Owner
  • 新增配置系统架构说明,涵盖 YAML 源文件、JSON Schema 结构描述、运行时只读查询等核心功能
  • 完善推荐目录结构和 Schema 示例,包括怪物、物品配置表的标准定义方式
  • 提供完整的接入模板,包含 csproj 配置、GameConfigHost 生命周期管理、GameConfigRuntime 读取入口
  • 添加运行时校验行为说明,支持必填字段、类型匹配、数值范围、字符串长度、正则表达式、数组长度等多种约束
  • 集成跨表引用功能,支持通过 x-gframework-ref-table 声明关联关系并进行有效性检查
  • 添加开发期热重载支持,可自动监听配置目录和 schema 文件变更并重载对应表格
  • 提供 VS Code 工具集成说明,包括配置浏览、raw 编辑、schema 打开、表单入口等功能
  • 补充生成器接入约定,从 *.schema.json 自动生成配置类型、表包装、注册辅助等代码
  • 添加完整的 Analyzer 规则文档,涵盖 GF_ConfigSchema_001 到 GF_ConfigSchema_008 等错误诊断码
  • 增加单元测试验证,确保消费者项目可以正常使用生成的聚合注册辅助和强类型访问入口

Summary by Sourcery

在配置模式中添加对声明式索引查找的支持,包括在生成端进行校验、在生成的表中进行惰性索引构建,以及更新后的文档和测试。

新功能:

  • 允许在符合条件的字段上,通过元数据 x-gframework-index(布尔值)在配置模式属性上声明一个生成的精确匹配查找索引。
  • 为被索引的属性生成惰性、只读的查找字典,并在启用索引时,通过这些索引路由 FindBy* / TryFindFirstBy* 辅助方法。

改进:

  • 校验查找索引元数据仅应用于顶层、必填、非主键、非引用的标量属性,当违反约束时发出诊断信息。
  • 在各个生成的表之间共享内部索引构建逻辑,并改进生成的 XML 文档,以体现基于索引的查询。

文档:

  • 扩展中文配置系统文档,描述 x-gframework-index 的用法、约束条件,以及它对生成的查询辅助方法的影响。

测试:

  • 添加单元测试和快照更新,以覆盖无效的查找索引元数据、不符合条件的索引目标,以及在消费方集成测试中成功的索引生成与使用。
Original summary in English

Summary by Sourcery

Add support for declarative indexed lookups in config schemas, with generator-side validation, lazy index construction in generated tables, and updated documentation and tests.

New Features:

  • Allow config schema properties to declare a generated exact-match lookup index via the x-gframework-index boolean metadata on eligible fields.
  • Generate lazy, read-only lookup dictionaries for indexed properties and route FindBy*/TryFindFirstBy* helpers through these indexes when enabled.

Enhancements:

  • Validate that lookup index metadata is only applied to top-level, required, non-key, non-reference scalar properties, emitting diagnostics when constraints are violated.
  • Share internal index-building logic across generated tables and improve generated XML documentation to reflect index-backed queries.

Documentation:

  • Extend the Chinese config system documentation to describe x-gframework-index usage, its constraints, and how it affects generated query helpers.

Tests:

  • Add unit tests and snapshot updates to cover invalid lookup index metadata, ineligible index targets, and successful index generation and usage in consumer integration tests.

Summary by CodeRabbit

  • 新功能

    • 支持在 JSON Schema 中通过 x-gframework-index: true 为满足条件的顶层标量字段声明精确匹配索引;相应的 FindBy*/TryFindFirstBy* 查询在这些字段上改为按需构建并使用只读索引以提升查找性能,外部 API 保持不变,并在运行时对 null 键做安全处理。
  • 文档

    • 更新配置系统文档,说明索引的启用条件与行为差异。
  • 错误报告

    • 当索引元数据不合法或应用于不合规目标时,生成器会报错并给出诊断提示。

- 新增配置系统架构说明,涵盖 YAML 源文件、JSON Schema 结构描述、运行时只读查询等核心功能
- 完善推荐目录结构和 Schema 示例,包括怪物、物品配置表的标准定义方式
- 提供完整的接入模板,包含 csproj 配置、GameConfigHost 生命周期管理、GameConfigRuntime 读取入口
- 添加运行时校验行为说明,支持必填字段、类型匹配、数值范围、字符串长度、正则表达式、数组长度等多种约束
- 集成跨表引用功能,支持通过 x-gframework-ref-table 声明关联关系并进行有效性检查
- 添加开发期热重载支持,可自动监听配置目录和 schema 文件变更并重载对应表格
- 提供 VS Code 工具集成说明,包括配置浏览、raw 编辑、schema 打开、表单入口等功能
- 补充生成器接入约定,从 *.schema.json 自动生成配置类型、表包装、注册辅助等代码
- 添加完整的 Analyzer 规则文档,涵盖 GF_ConfigSchema_001 到 GF_ConfigSchema_008 等错误诊断码
- 增加单元测试验证,确保消费者项目可以正常使用生成的聚合注册辅助和强类型访问入口
@coderabbitai

coderabbitai Bot commented Apr 8, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de085662-5fea-4f23-a82a-ce42255d7fd6

📥 Commits

Reviewing files that changed from the base of the PR and between 9b13985 and 0171794.

📒 Files selected for processing (3)
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
  • GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Code Quality & Security
🧰 Additional context used
📓 Path-based instructions (2)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: LoggerGenerator must automatically generate log fields and logging helper methods for classes decorated with [Log] attribute
PriorityGenerator must generate priority comparison implementations for classes decorated with [Priority] attribute
EnumExtensionsGenerator must generate enum extension capabilities for enums decorated with [GenerateEnumExtensions] attribute
ContextAwareGenerator must automatically implement IContextAware boilerplate logic for classes decorated with [ContextAware] attribute

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable in C# code
XML documentation comments MUST explain intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly in XML comments
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds, compatibility constraints, edge cases, registration order, lifecycle sequencing, or generated code assumptions
Avoid obvious comments such as // increment i in C# code
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, the semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling in C# code
Comments MUST NOT be trivial, redundant, or misleading; prefer explaining why and when, not just what
Missing required documentation is a coding standards violation in C# code
Do not rely on implicit imports in C# code; declare every required using explicitly
Write null-safe C# code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase ...

Files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
**/*SourceGenerators.Tests/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*SourceGenerators.Tests/**/*.cs: Source generator changes MUST be covered by generator tests
Preserve snapshot-based verification patterns already used in the repository for source generator tests

Files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
🧠 Learnings (10)
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators/**/*.cs : When source generator behavior changes intentionally, update snapshots together with the implementation

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators.Tests/**/*.cs : Source generator changes MUST be covered by generator tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators.Tests/**/*.cs : Preserve snapshot-based verification patterns already used in the repository for source generator tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Public API changes must be covered by unit or integration tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : When a public API defines multiple contract branches, tests MUST cover the meaningful variants, including null, empty, default, and filtered inputs when those branches change behavior

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Keep tests focused on observable behavior, not implementation trivia

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Every non-trivial feature, bug fix, or behavior change MUST include tests or an explicit justification for why a test is not practical

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators/**/*.cs : Keep source generators deterministic and free of hidden environment or network dependencies

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
🔇 Additional comments (7)
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt (2)

60-111: 索引构建逻辑实现良好。

BuildLookupIndex<TProperty> 方法的防御性设计值得肯定:

  1. 即使 TPropertynotnull 约束,仍在 Line 88 检查 key is null 以防止格式错误的 YAML 数据污染懒加载索引。
  2. 文档注释(Lines 75-77)清晰说明了为什么在 notnull 约束下仍需检查 null 的原因。
  3. 使用 AsReadOnly() 而非 ToArray() 避免不必要的数组分配。

121-161: 查找方法的 null 防护已正确实现。

FindByNameTryFindFirstByName 方法在访问 _nameIndex.Value.TryGetValue 之前添加了 null 检查(Lines 123-126 和 147-151),确保与非索引路径(使用 EqualityComparer<T>.Default.Equals 可安全处理 null)的行为一致。

GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs (5)

229-315: 测试覆盖运行时 null key 跳过逻辑。

此测试验证生成的索引构建代码包含 if (key is null) 防护和相关注释,符合快照验证模式。测试结构与现有测试保持一致。


358-400: 诊断测试覆盖非布尔值元数据场景。

测试验证当 x-gframework-index 值为字符串 "yes" 而非布尔值时,生成器正确报告 GF_ConfigSchema_008 错误诊断。断言检查诊断 ID、严重性及消息关键词,符合预期。


402-450: 诊断测试覆盖不合规索引目标。

测试验证对嵌套属性 reward.rarity 声明 x-gframework-index: true 时,生成器正确报告诊断并包含 "top-level required non-key scalar" 提示信息。这与 SchemaConfigGenerator.csTryValidateIndexedLookupEligibilityisDirectChildOfRoot 检查逻辑对应。


452-537: 边界情况测试覆盖带点号的根级属性名。

此测试验证 schema 属性名 "display.name"(名称本身包含点号)作为根级直接子属性时,不会被错误识别为嵌套路径。测试确认生成器正确生成 FindByDisplayName_displayNameIndex,且不产生诊断错误。这是一个重要的边界情况覆盖。


739-760: 更新的断言正确验证索引基础设施生成。

断言更新涵盖:

  1. 索引字段 _nameIndex 和构建方法 BuildNameIndex 的存在性
  2. null 检查 if (value is null) 和字典查找 _nameIndex.Value.TryGetValue
  3. 使用 AsReadOnly() 而非 ToArray()
  4. 非索引属性 hp 不生成 _hpIndex(Line 751)

这确保了索引仅为声明 x-gframework-index: true 的属性生成。


📝 Walkthrough

Walkthrough

引入并解析 JSON Schema 元数据 x-gframework-index,对其合法性进行校验(新增诊断 GF_ConfigSchema_008),在符合条件的顶层标量属性上生成按需构建的只读查找索引并调整相应生成的查找辅助方法,更新测试、快照与文档。

Changes

Cohort / File(s) Summary
Schema 测试固件
GFramework.Game.Tests/schemas/monster.schema.json, GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
monster schema 的 namefaction 属性加入 x-gframework-index: true 测试元数据,更新测试夹具。
源生成器核心
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs, GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
新增对 x-gframework-index 的布尔解析与校验逻辑,增加 SchemaPropertySpec.IsIndexedLookup,添加诊断 InvalidLookupIndexMetadata (GF_ConfigSchema_008),并在解析阶段拒绝不合规的索引声明。
生成器产物与生成逻辑
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt, GFramework.SourceGenerators/Config/...
为符合条件的顶层标量属性生成 Lazy 索引字段(如 _nameIndex)、BuildLookupIndex<TProperty>()、并将 FindBy*/TryFindFirstBy* 的实现从线性扫描切换为基于索引的查找(含 null-guard 行为)。
单元测试与快照
GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs, GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
新增测试覆盖:非布尔或不合格目标应触发 GF_ConfigSchema_008;支持带点号键名的顶层索引;更新并扩展快照以包含索引相关成员/方法。
诊断发布说明
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
记录新增诊断 GF_ConfigSchema_008(错误级别)。
文档
docs/zh-CN/game/config-system.md
新增 x-gframework-index 的使用说明及其适用约束(顶层、必填、非主键、非引用标量)和对生成索引行为的说明。

Sequence Diagram(s)

sequenceDiagram
    participant Parser as Schema Parser
    participant Validator as Eligibility Validator
    participant Diagnostics as Diagnostic System
    participant Generator as Code Generator
    participant Output as Generated Code

    Parser->>Parser: 读取属性元数据(x-gframework-index)
    Parser->>Validator: 尝试解析为布尔值
    alt 非布尔或解析失败
        Validator->>Diagnostics: 触发 GF_ConfigSchema_008 错误
        Diagnostics->>Output: 报告诊断,索引生成被拒绝
    else 为布尔且为 true/false
        Validator->>Validator: 校验资格(顶层、必填、非主键、非引用、标量)
        alt 不合格
            Validator->>Diagnostics: 触发 GF_ConfigSchema_008 错误
            Diagnostics->>Output: 报告诊断,索引生成被拒绝
        else 合格且为 true
            Validator->>Generator: 标记属性为 IsIndexedLookup
            Generator->>Generator: 生成 Lazy 索引字段与 BuildLookupIndex<T>
            Generator->>Generator: 将 FindBy*/TryFindFirstBy* 改为索引查找(含 null-guard)
            Generator->>Output: 输出修改后的表类及辅助方法
        end
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • PR #186: 在 SchemaConfigGenerator、生成器测试/快照与生成表类行为上有直接相关的修改(索引/查询辅助生成相关)。
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰准确地反映了主要变更内容,即实现x-gframework-index索引元数据支持。标题简洁、具体,涵盖了本次PR的核心功能。
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/game-config-system

Comment @coderabbitai help to get the list of available commands and usage tips.

@deepsource-io

deepsource-io Bot commented Apr 8, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 3109bea...43b95c7 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
C# Apr 8, 2026 1:52a.m. Review ↗
Secrets Apr 8, 2026 1:52a.m. Review ↗

@sourcery-ai

sourcery-ai Bot commented Apr 8, 2026

Copy link
Copy Markdown

Reviewer's Guide

通过 x-gframework-index 元数据为配置 schema 属性添加可选择开启的生成查找索引支持,包括生成器逻辑、验证诊断、测试以及游戏配置系统的文档更新。

生成配置表中索引查找解析的时序图

sequenceDiagram
    actor Developer
    participant MonsterTable
    participant NameIndex as nameIndex Lazy
    participant ConfigTable as IConfigTable

    Developer->>MonsterTable: FindByName("Slime")
    MonsterTable->>NameIndex: get Value
    alt index not yet built
        NameIndex->>MonsterTable: invoke BuildNameIndex()
        MonsterTable->>MonsterTable: BuildNameIndex()
        MonsterTable->>MonsterTable: BuildLookupIndex(config => config.Name)
        MonsterTable->>ConfigTable: All()
        ConfigTable-->>MonsterTable: IEnumerable<MonsterConfig>
        loop for each candidate
            MonsterTable->>MonsterTable: key = candidate.Name
            MonsterTable->>MonsterTable: add candidate to bucket[key]
        end
        MonsterTable->>NameIndex: return IReadOnlyDictionary<string, IReadOnlyList<MonsterConfig>>
    else index already built
        NameIndex-->>MonsterTable: cached IReadOnlyDictionary<string, IReadOnlyList<MonsterConfig>>
    end

    MonsterTable->>NameIndex: TryGetValue("Slime", out matches)
    alt matches found
        NameIndex-->>MonsterTable: matches list
        MonsterTable-->>Developer: IReadOnlyList<MonsterConfig>
    else no matches
        MonsterTable-->>Developer: empty array
    end
Loading

生成配置表查找索引支持的类图

classDiagram
    direction LR

    class SchemaConfigGenerator {
        +GenerateTableClass(schema SchemaFileSpec) string
        -CollectQueryableProperties(schema SchemaFileSpec) IEnumerable~SchemaPropertySpec~
        -AppendIndexedLookupBuilderMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -AppendSharedLookupIndexBuilderMethod(builder StringBuilder, schema SchemaFileSpec) void
        -AppendFindByPropertyMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -AppendTryFindFirstByPropertyMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -ParseProperty(filePath string, property JsonProperty, isRequired bool, displayPath string) ParsedPropertyResult
        -ParseArrayProperty(filePath string, property JsonProperty, isRequired bool, displayPath string, propertyName string, title string, description string, refTableName string, isIndexedLookup bool) ParsedPropertyResult
        -TryValidateIndexedLookupEligibility(filePath string, schemaName string, displayPath string, isRequired bool, refTableName string, diagnostic out Diagnostic) bool
        -IsTopLevelPropertyDisplayPath(displayPath string) bool
        -TryGetMetadataBoolean(element JsonElement, propertyName string) (bool? Value, string Diagnostic)
    }

    class SchemaFileSpec {
        +TableName string
        +ClassName string
        +KeyClrType string
    }

    class SchemaPropertySpec {
        +SchemaName string
        +DisplayPath string
        +PropertyName string
        +IsRequired bool
        +Title string
        +Description string
        +IsIndexedLookup bool
        +TypeSpec SchemaTypeSpec
    }

    class SchemaTypeSpec {
        +ClrType string
        +NodeKind SchemaNodeKind
        +JsonType string
        +IsArray bool
    }

    class MonsterTable {
        -_inner IConfigTable~int, MonsterConfig~
        -_nameIndex Lazy~IReadOnlyDictionary~string, IReadOnlyList~MonsterConfig~~
        +MonsterTable(inner IConfigTable~int, MonsterConfig~)
        +All() IEnumerable~MonsterConfig~
        +Get(int id) MonsterConfig
        +TryGet(int id, out MonsterConfig result) bool
        +FindByName(string value) IReadOnlyList~MonsterConfig~
        +TryFindFirstByName(string value, out MonsterConfig result) bool
        -BuildNameIndex() IReadOnlyDictionary~string, IReadOnlyList~MonsterConfig~
        -BuildLookupIndex~TProperty~(keySelector Func~MonsterConfig, TProperty~) IReadOnlyDictionary~TProperty, IReadOnlyList~MonsterConfig~
    }

    class IConfigTable~TKey, TValue~ {
        <<interface>>
        +All() IEnumerable~TValue~
        +Get(TKey key) TValue
        +TryGet(TKey key, out TValue value) bool
    }

    SchemaConfigGenerator --> SchemaFileSpec : reads
    SchemaConfigGenerator --> SchemaPropertySpec : constructs
    SchemaConfigGenerator --> SchemaTypeSpec : uses
    SchemaConfigGenerator ..> MonsterTable : generates source

    MonsterTable ..|> IConfigTable~int, MonsterConfig~ : wraps
    MonsterTable --> SchemaPropertySpec : generated from IsIndexedLookup properties

    SchemaPropertySpec --> SchemaTypeSpec : has

    class MonsterConfig {
        +Id int
        +Name string
        +Hp int?
        +Faction string
    }
Loading

File-Level Changes

Change Details Files
引入 x-gframework-index schema 元数据以及用于约束哪些属性可以声明索引查找的验证规则。
  • 新增 LookupIndexMetadataKey 常量和 TryGetMetadataBoolean 辅助方法,用于从 schema 元素中读取布尔类型元数据。
  • 通过 TryValidateIndexedLookupEligibility 校验查找索引元数据的类型与适用性,将索引限制在顶层的、必填的、非主键、非引用的标量属性上。
  • 禁止在对象和数组属性上使用 x-gframework-index,并返回带有详细原因的 GF_ConfigSchema_008 诊断信息。
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
为符合条件的属性生成惰性、只读的查找索引以及基于索引的查询帮助方法。
  • 扩展 SchemaPropertySpec,增加 IsIndexedLookup 标记,并在解析标量与数组属性时向下传递该标记。
  • GenerateTableClass 中收集带索引的属性,生成 Lazy<IReadOnlyDictionary<TKey, IReadOnlyList<TConfig>>> 字段,并在生成的表包装类构造函数中完成初始化。
  • 新增共享的 BuildLookupIndex<TProperty> 辅助方法以及按属性区分的 Build<Property>Index 构建方法,用于构造基于快照的查找字典。
  • 更新 FindBy*TryFindFirstBy* 的代码生成逻辑:当 IsIndexedLookuptrue 时使用索引字典,否则回退到线性扫描,并相应调整 XML 文档注释。
  • 新增 ToCamelCase 辅助方法,用于生成私有索引字段名。
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
添加测试和快照,覆盖查找索引元数据验证以及生成的基于索引的 API。
  • 新增单元测试,确保非布尔类型的 x-gframework-index 元数据会以清晰的错误信息报告 GF_ConfigSchema_008
  • 新增单元测试,确保对不符合条件的目标(例如嵌套属性)使用 x-gframework-index 时也会报告带路径信息的 GF_ConfigSchema_008
  • 更新生成器测试,断言对于带索引的属性会生成索引字段、构建方法以及基于索引的查询逻辑,而对未索引的属性不会生成这些内容。
  • 更新集成测试与测试 schema(如 monster.schema.json),为部分字段添加 x-gframework-index 以进行端到端验证。
  • 刷新 MonsterTable 的生成快照以包含索引相关成员和元数据。
GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
GFramework.Game.Tests/schemas/monster.schema.json
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
为新的配置系统索引元数据及其运行时行为编写文档。
  • 扩展中文配置系统文档,描述 x-gframework-index 的使用方式、约束条件,以及它如何将 FindBy*/TryFindFirstBy* 从线性扫描切换为惰性的精确匹配索引。
  • 明确说明只有显式声明 x-gframework-index:true 的字段才会获得惰性只读索引;其余字段仍然使用基于 All() 的线性扫描以避免额外的运行时开销。
docs/zh-CN/game/config-system.md
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md

Tips and commands

Interacting with Sourcery

  • 触发新的代码审查: 在 pull request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在某条审查评论下回复,请求 Sourcery 从该评论创建 issue。你也可以直接回复 @sourcery-ai issue 来基于该评论创建 issue。
  • 生成 pull request 标题: 在 pull request 标题任意位置写上 @sourcery-ai,即可随时生成标题。你也可以在 pull request 中评论 @sourcery-ai title 来(重新)生成标题。
  • 生成 pull request 摘要: 在 pull request 正文的任意位置写上 @sourcery-ai summary,即可在该位置生成 PR 摘要。你也可以在 pull request 中评论 @sourcery-ai summary 来(重新)生成摘要。
  • 生成审查指南: 在 pull request 中评论 @sourcery-ai guide,即可随时(重新)生成审查者指南。
  • 一次性解决所有 Sourcery 评论: 在 pull request 中评论 @sourcery-ai resolve,将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不想再看到它们,这非常有用。
  • 撤销所有 Sourcery 审查: 在 pull request 中评论 @sourcery-ai dismiss,撤销所有现有的 Sourcery 审查。若你想从头开始一次全新的审查,尤其有用——不要忘了再评论一次 @sourcery-ai review 来触发新审查!

Customizing Your Experience

打开你的 dashboard 以:

  • 启用或禁用诸如 Sourcery 自动生成 PR 摘要、审查者指南等审查功能。
  • 修改审查语言。
  • 添加、移除或编辑自定义审查说明。
  • 调整其他审查设置。

Getting Help

Original review guide in English

Reviewer's Guide

Add opt-in generated lookup index support for config schema properties via x-gframework-index metadata, including generator logic, validation diagnostics, tests, and documentation updates for the game config system.

Sequence diagram for indexed lookup resolution in generated config table

sequenceDiagram
    actor Developer
    participant MonsterTable
    participant NameIndex as nameIndex Lazy
    participant ConfigTable as IConfigTable

    Developer->>MonsterTable: FindByName("Slime")
    MonsterTable->>NameIndex: get Value
    alt index not yet built
        NameIndex->>MonsterTable: invoke BuildNameIndex()
        MonsterTable->>MonsterTable: BuildNameIndex()
        MonsterTable->>MonsterTable: BuildLookupIndex(config => config.Name)
        MonsterTable->>ConfigTable: All()
        ConfigTable-->>MonsterTable: IEnumerable<MonsterConfig>
        loop for each candidate
            MonsterTable->>MonsterTable: key = candidate.Name
            MonsterTable->>MonsterTable: add candidate to bucket[key]
        end
        MonsterTable->>NameIndex: return IReadOnlyDictionary<string, IReadOnlyList<MonsterConfig>>
    else index already built
        NameIndex-->>MonsterTable: cached IReadOnlyDictionary<string, IReadOnlyList<MonsterConfig>>
    end

    MonsterTable->>NameIndex: TryGetValue("Slime", out matches)
    alt matches found
        NameIndex-->>MonsterTable: matches list
        MonsterTable-->>Developer: IReadOnlyList<MonsterConfig>
    else no matches
        MonsterTable-->>Developer: empty array
    end
Loading

Class diagram for generated config table lookup index support

classDiagram
    direction LR

    class SchemaConfigGenerator {
        +GenerateTableClass(schema SchemaFileSpec) string
        -CollectQueryableProperties(schema SchemaFileSpec) IEnumerable~SchemaPropertySpec~
        -AppendIndexedLookupBuilderMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -AppendSharedLookupIndexBuilderMethod(builder StringBuilder, schema SchemaFileSpec) void
        -AppendFindByPropertyMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -AppendTryFindFirstByPropertyMethod(builder StringBuilder, schema SchemaFileSpec, property SchemaPropertySpec) void
        -ParseProperty(filePath string, property JsonProperty, isRequired bool, displayPath string) ParsedPropertyResult
        -ParseArrayProperty(filePath string, property JsonProperty, isRequired bool, displayPath string, propertyName string, title string, description string, refTableName string, isIndexedLookup bool) ParsedPropertyResult
        -TryValidateIndexedLookupEligibility(filePath string, schemaName string, displayPath string, isRequired bool, refTableName string, diagnostic out Diagnostic) bool
        -IsTopLevelPropertyDisplayPath(displayPath string) bool
        -TryGetMetadataBoolean(element JsonElement, propertyName string) (bool? Value, string Diagnostic)
    }

    class SchemaFileSpec {
        +TableName string
        +ClassName string
        +KeyClrType string
    }

    class SchemaPropertySpec {
        +SchemaName string
        +DisplayPath string
        +PropertyName string
        +IsRequired bool
        +Title string
        +Description string
        +IsIndexedLookup bool
        +TypeSpec SchemaTypeSpec
    }

    class SchemaTypeSpec {
        +ClrType string
        +NodeKind SchemaNodeKind
        +JsonType string
        +IsArray bool
    }

    class MonsterTable {
        -_inner IConfigTable~int, MonsterConfig~
        -_nameIndex Lazy~IReadOnlyDictionary~string, IReadOnlyList~MonsterConfig~~
        +MonsterTable(inner IConfigTable~int, MonsterConfig~)
        +All() IEnumerable~MonsterConfig~
        +Get(int id) MonsterConfig
        +TryGet(int id, out MonsterConfig result) bool
        +FindByName(string value) IReadOnlyList~MonsterConfig~
        +TryFindFirstByName(string value, out MonsterConfig result) bool
        -BuildNameIndex() IReadOnlyDictionary~string, IReadOnlyList~MonsterConfig~
        -BuildLookupIndex~TProperty~(keySelector Func~MonsterConfig, TProperty~) IReadOnlyDictionary~TProperty, IReadOnlyList~MonsterConfig~
    }

    class IConfigTable~TKey, TValue~ {
        <<interface>>
        +All() IEnumerable~TValue~
        +Get(TKey key) TValue
        +TryGet(TKey key, out TValue value) bool
    }

    SchemaConfigGenerator --> SchemaFileSpec : reads
    SchemaConfigGenerator --> SchemaPropertySpec : constructs
    SchemaConfigGenerator --> SchemaTypeSpec : uses
    SchemaConfigGenerator ..> MonsterTable : generates source

    MonsterTable ..|> IConfigTable~int, MonsterConfig~ : wraps
    MonsterTable --> SchemaPropertySpec : generated from IsIndexedLookup properties

    SchemaPropertySpec --> SchemaTypeSpec : has

    class MonsterConfig {
        +Id int
        +Name string
        +Hp int?
        +Faction string
    }
Loading

File-Level Changes

Change Details Files
Introduce x-gframework-index schema metadata and validation rules for which properties may declare indexed lookups.
  • Add LookupIndexMetadataKey constant and TryGetMetadataBoolean helper to read boolean metadata from schema elements.
  • Validate lookup index metadata type and eligibility using TryValidateIndexedLookupEligibility, restricting indexes to top-level required non-key non-reference scalar properties.
  • Disallow x-gframework-index on object and array properties, returning GF_ConfigSchema_008 diagnostics with detailed reasons.
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
Generate lazy, read-only lookup indexes and index-backed query helpers for eligible properties.
  • Extend SchemaPropertySpec to carry IsIndexedLookup flag and propagate it when parsing scalar and array properties.
  • In GenerateTableClass, collect indexed properties, emit Lazy<IReadOnlyDictionary<TKey, IReadOnlyList>> fields and initialize them in the generated table wrapper constructor.
  • Add shared BuildLookupIndex helper and per-property BuildIndex builder methods to materialize snapshot-based lookup dictionaries.
  • Update FindBy* and TryFindFirstBy* generation to use the indexed dictionaries when IsIndexedLookup is true, falling back to linear scans otherwise, and adjust XML doc comments accordingly.
  • Add ToCamelCase helper for generating private index field names.
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
Add tests and snapshots to cover lookup index metadata validation and generated index-backed APIs.
  • Add unit test ensuring non-boolean x-gframework-index metadata reports GF_ConfigSchema_008 with a clear error message.
  • Add unit test ensuring ineligible targets (e.g., nested properties) for x-gframework-index also report GF_ConfigSchema_008 with path details.
  • Update generator tests to assert presence of index fields, builders, and index-backed query logic for indexed properties, and absence for non-indexed ones.
  • Update integration tests and test schemas (e.g., monster.schema.json) to mark selected fields with x-gframework-index for end-to-end validation.
  • Refresh snapshot for MonsterTable generation to include index-related members and metadata.
GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
GFramework.Game.Tests/schemas/monster.schema.json
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
Document the new config-system index metadata and its runtime behavior.
  • Extend Chinese config-system docs to describe x-gframework-index usage, constraints, and how it switches FindBy*/TryFindFirstBy* from linear scans to lazy exact-match indexes.
  • Clarify that only fields explicitly declaring x-gframework-index:true get lazy read-only indexes; others keep linear All() scans to avoid extra runtime cost.
docs/zh-CN/game/config-system.md
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Comment thread GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs Outdated

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我在这里给出了一些总体反馈:

  • 用于描述无效查询索引元数据的错误消息文本(例如:"Only top-level required non-key scalar properties...")在多个诊断调用位置被重复使用;建议将这些文本提取到常量或辅助方法中,以保持消息的一致性并降低维护成本。
  • 在 BuildLookupIndex 中,你目前会分配一个中间 Dictionary,并通过 ToArray/Array.AsReadOnly 将每个 List 复制一份,然后再包装成 ReadOnlyDictionary;如果不变性语义允许,可以通过直接复用原有列表并使用 List.AsReadOnly() 来避免额外的分配,并且可以考虑直接返回 IDictionary/IReadOnlyDictionary,而不是构造一个新的字典实例。
给 AI 代理的提示
Please address the comments from this code review:

## Overall Comments
- The error message text for invalid lookup index metadata (e.g., "Only top-level required non-key scalar properties...") is duplicated in several diagnostic call sites; consider extracting these into constants or a helper to keep messaging consistent and easier to maintain.
- In BuildLookupIndex, you currently allocate an intermediate Dictionary plus copy each List via ToArray/Array.AsReadOnly before wrapping in ReadOnlyDictionary; if immutability semantics allow it, you could avoid the extra allocations by reusing the original lists with List<T>.AsReadOnly() and possibly returning IDictionary/IReadOnlyDictionary directly instead of materializing a new dictionary.

Sourcery 对开源项目是免费的——如果你觉得我们的评审有帮助,欢迎分享 ✨
帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码评审。
Original comment in English

Hey - I've left some high level feedback:

  • The error message text for invalid lookup index metadata (e.g., "Only top-level required non-key scalar properties...") is duplicated in several diagnostic call sites; consider extracting these into constants or a helper to keep messaging consistent and easier to maintain.
  • In BuildLookupIndex, you currently allocate an intermediate Dictionary plus copy each List via ToArray/Array.AsReadOnly before wrapping in ReadOnlyDictionary; if immutability semantics allow it, you could avoid the extra allocations by reusing the original lists with List.AsReadOnly() and possibly returning IDictionary/IReadOnlyDictionary directly instead of materializing a new dictionary.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The error message text for invalid lookup index metadata (e.g., "Only top-level required non-key scalar properties...") is duplicated in several diagnostic call sites; consider extracting these into constants or a helper to keep messaging consistent and easier to maintain.
- In BuildLookupIndex, you currently allocate an intermediate Dictionary plus copy each List via ToArray/Array.AsReadOnly before wrapping in ReadOnlyDictionary; if immutability semantics allow it, you could avoid the extra allocations by reusing the original lists with List<T>.AsReadOnly() and possibly returning IDictionary/IReadOnlyDictionary directly instead of materializing a new dictionary.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs (1)

733-754: ⚠️ Potential issue | 🟠 Major

索引缓存挂在 wrapper 实例上会把性能收益和热重载语义变成二选一

这些 Lazy 索引按生成的 table wrapper 实例缓存,而同文件后面的 Get*Table / TryGet*Table helper 又是每次访问都新建 wrapper。这样调用方要么现取现用,导致每个 wrapper 第一次查询都重新全表建索引;要么长期持有 wrapper 复用缓存,但底层表热重载后 FindBy* / TryFindFirstBy* 仍会命中旧 bucket。更稳妥的是把索引缓存绑定到运行时表的版本/重载失效点,或者继续按 All() 现查以保持 reload 一致性。

Also applies to: 1613-1622, 1682-1693

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs` around lines 733
- 754, The generated Lazy index fields (e.g.
_{ToCamelCase(property.PropertyName)}Index) are attached to the wrapper instance
in the constructor (public {schema.TableName}(...)) which conflicts with helpers
that allocate new wrappers (Get*Table/TryGet*Table) and with runtime reload
semantics used by FindBy*/TryFindFirstBy*; change the strategy so the index is
either: (a) moved off the wrapper and cached by the runtime table
instance/version (inspect the inner IConfigTable's reload/version token and
store the computed IReadOnlyDictionary keyed by that token so
Build{property.PropertyName}Index is recomputed on reload), or (b) remove
per-wrapper Lazy caching and compute indexes from inner.All() on each lookup to
preserve reload consistency; update the constructor to stop creating per-wrapper
Lazy fields and adjust any call sites for Build{property.PropertyName}Index,
Get*Table/TryGet*Table and FindBy*/TryFindFirstBy* accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt`:
- Around line 111-119: FindByName currently calls
_nameIndex.Value.TryGetValue(value, out var matches) which throws if value is
null; add an explicit null guard at the start of FindByName that returns
Array.Empty<MonsterConfig>() when value is null so behavior matches the
linear-scan path (which uses EqualityComparer<string>.Default.Equals and accepts
null). Update the other indexed lookup site that calls
_nameIndex.Value.TryGetValue(...) the same way to ensure consistent null
handling across index lookups.

In `@GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs`:
- Around line 302-307: The code is incorrectly using the presentation string
displayPath to infer whether a field is top-level (causing valid root keys with
'.' or '[' to be misclassified); update the logic so
TryValidateIndexedLookupEligibility (and its callers) no longer inspect
displayPath for nesting—add and pass an explicit structural indicator (e.g.,
depth or isDirectChildOfRoot) from the parsing stage into
TryValidateIndexedLookupEligibility instead of relying on displayPath, then use
that explicit flag in the isIndexedLookup validation path that returns
ParsedPropertyResult.FromDiagnostic; apply the same change to the other
occurrences noted (around the other call sites).

---

Outside diff comments:
In `@GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs`:
- Around line 733-754: The generated Lazy index fields (e.g.
_{ToCamelCase(property.PropertyName)}Index) are attached to the wrapper instance
in the constructor (public {schema.TableName}(...)) which conflicts with helpers
that allocate new wrappers (Get*Table/TryGet*Table) and with runtime reload
semantics used by FindBy*/TryFindFirstBy*; change the strategy so the index is
either: (a) moved off the wrapper and cached by the runtime table
instance/version (inspect the inner IConfigTable's reload/version token and
store the computed IReadOnlyDictionary keyed by that token so
Build{property.PropertyName}Index is recomputed on reload), or (b) remove
per-wrapper Lazy caching and compute indexes from inner.All() on each lookup to
preserve reload consistency; update the constructor to stop creating per-wrapper
Lazy fields and adjust any call sites for Build{property.PropertyName}Index,
Get*Table/TryGet*Table and FindBy*/TryFindFirstBy* accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 29e8b6b0-2e58-4fc4-b339-54271930ee59

📥 Commits

Reviewing files that changed from the base of the PR and between 3109bea and 43b95c7.

📒 Files selected for processing (9)
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.Game.Tests/schemas/monster.schema.json
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
  • GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
  • GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
  • GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
  • docs/zh-CN/game/config-system.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Analyze (C#)
  • GitHub Check: Build and Test
  • GitHub Check: Code Quality & Security
🧰 Additional context used
📓 Path-based instructions (6)
**/*.cs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.cs: LoggerGenerator must automatically generate log fields and logging helper methods for classes decorated with [Log] attribute
PriorityGenerator must generate priority comparison implementations for classes decorated with [Priority] attribute
EnumExtensionsGenerator must generate enum extension capabilities for enums decorated with [GenerateEnumExtensions] attribute
ContextAwareGenerator must automatically implement IContextAware boilerplate logic for classes decorated with [ContextAware] attribute

**/*.cs: All public, protected, and internal types and members MUST include XML documentation comments (///) with <summary>, <param>, <returns>, <exception>, and <remarks> where applicable in C# code
XML documentation comments MUST explain intent, contract, and usage constraints instead of restating syntax
If a member participates in lifecycle, threading, registration, or disposal behavior, document that behavior explicitly in XML comments
Add inline comments for non-trivial logic, concurrency or threading behavior, performance-sensitive paths, workarounds, compatibility constraints, edge cases, registration order, lifecycle sequencing, or generated code assumptions
Avoid obvious comments such as // increment i in C# code
Generated logic and source generator pipelines MUST explain what is generated, why it is generated, the semantic assumptions the generator relies on, and any diagnostics or fallback behavior
Methods with non-trivial logic MUST document the core idea, key decisions, and edge case handling in C# code
Comments MUST NOT be trivial, redundant, or misleading; prefer explaining why and when, not just what
Missing required documentation is a coding standards violation in C# code
Do not rely on implicit imports in C# code; declare every required using explicitly
Write null-safe C# code that respects nullable annotations instead of suppressing warnings by default
Use the namespace pattern GFramework.{Module}.{Feature} with PascalCase ...

Files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
**/*SourceGenerators.Tests/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*SourceGenerators.Tests/**/*.cs: Source generator changes MUST be covered by generator tests
Preserve snapshot-based verification patterns already used in the repository for source generator tests

Files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
**/*SourceGenerators/**/*.cs

📄 CodeRabbit inference engine (AGENTS.md)

**/*SourceGenerators/**/*.cs: When source generator behavior changes intentionally, update snapshots together with the implementation
Keep source generators deterministic and free of hidden environment or network dependencies

Files:

  • GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
docs/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Documentation must be located in docs/ directory with Chinese content in docs/zh-CN/

Files:

  • docs/zh-CN/game/config-system.md
{README.md,docs/**/*.md,docs/zh-CN/**/*.md}

📄 CodeRabbit inference engine (AGENTS.md)

{README.md,docs/**/*.md,docs/zh-CN/**/*.md}: Update the relevant README.md or docs/ page when behavior, setup steps, architecture guidance, or user-facing examples change
Keep code samples, package names, and command examples in documentation aligned with the current repository state
Prefer documenting behavior and design intent in documentation, not only API surface
For integration-oriented features such as the AI-First config system, documentation MUST cover project directory layout and file conventions, required project or package wiring, minimal working usage example, and migration or compatibility notes when behavior changes

Files:

  • docs/zh-CN/game/config-system.md
docs/zh-CN/**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

When a feature is added, removed, renamed, or substantially refactored, contributors MUST update or create the corresponding user-facing integration documentation in docs/zh-CN/ in the same change

Files:

  • docs/zh-CN/game/config-system.md
🧠 Learnings (9)
📓 Common learnings
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to docs/zh-CN/**/*.md : When a feature is added, removed, renamed, or substantially refactored, contributors MUST update or create the corresponding user-facing integration documentation in `docs/zh-CN/` in the same change
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to {README.md,docs/**/*.md,docs/zh-CN/**/*.md} : For integration-oriented features such as the AI-First config system, documentation MUST cover project directory layout and file conventions, required project or package wiring, minimal working usage example, and migration or compatibility notes when behavior changes
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators/**/*.cs : When source generator behavior changes intentionally, update snapshots together with the implementation

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators.Tests/**/*.cs : Source generator changes MUST be covered by generator tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*SourceGenerators.Tests/**/*.cs : Preserve snapshot-based verification patterns already used in the repository for source generator tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Public API changes must be covered by unit or integration tests

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
📚 Learning: 2026-04-06T12:45:43.921Z
Learnt from: GeWuYou
Repo: GeWuYou/GFramework PR: 190
File: GFramework.Game/Config/GameConfigBootstrap.cs:1-3
Timestamp: 2026-04-06T12:45:43.921Z
Learning: In the GeWuYou/GFramework repository, C# files may omit explicit `using System*` imports because the project-wide `GlobalUsings.cs` (referenced via manual global `using` directives) supplies common namespaces (e.g., `System`, `System.Threading`, `System.Threading.Tasks`). During code review, do not flag missing `using System...` directives in `.cs` files as long as `GlobalUsings.cs` is present/used to provide those namespaces.

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs
  • GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs
  • GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs
  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
  • GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to docs/zh-CN/**/*.md : When a feature is added, removed, renamed, or substantially refactored, contributors MUST update or create the corresponding user-facing integration documentation in `docs/zh-CN/` in the same change

Applied to files:

  • docs/zh-CN/game/config-system.md
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to {README.md,docs/**/*.md,docs/zh-CN/**/*.md} : For integration-oriented features such as the AI-First config system, documentation MUST cover project directory layout and file conventions, required project or package wiring, minimal working usage example, and migration or compatibility notes when behavior changes

Applied to files:

  • docs/zh-CN/game/config-system.md
📚 Learning: 2026-04-06T10:00:34.101Z
Learnt from: CR
Repo: GeWuYou/GFramework PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-06T10:00:34.101Z
Learning: Applies to **/*.Tests.cs : Regression fixes should include a test that fails before the fix and passes after it

Applied to files:

  • GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs
🔇 Additional comments (7)
docs/zh-CN/game/config-system.md (1)

368-379: 索引元数据行为边界说明清晰,文档更新到位。

这次补充把“显式声明才建索引”和“未声明保持线性扫描”讲清楚了,且明确了 API 外观不变,便于消费者评估兼容性。

As per coding guidelines "For integration-oriented features such as the AI-First config system, documentation MUST cover ... migration or compatibility notes when behavior changes".

Also applies to: 398-399

GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.cs (1)

82-82: 测试输入已正确对齐新索引元数据语义。

name 字段标记为 x-gframework-index: true,能稳定驱动对应快照差异。

Based on learnings "Source generator changes MUST be covered by generator tests" and "Preserve snapshot-based verification patterns already used in the repository for source generator tests".

GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs (1)

223-224: 消费者集成测试样本与索引特性已一致。

namefaction 标记为索引字段后,现有断言可以真实覆盖生成查询辅助在消费者项目中的使用路径。

Based on learnings "Public API changes must be covered by unit or integration tests".

Also applies to: 232-233

GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md (1)

28-28: 新诊断规则已正确登记到 Unshipped 列表。

GF_ConfigSchema_008 的发布跟踪补充完整。

GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs (1)

89-98: 新增诊断描述符定义规范且可读。

GF_ConfigSchema_008 的消息模板参数位设计合理,便于输出具体字段路径与违规原因。

GFramework.Game.Tests/schemas/monster.schema.json (1)

19-19: 测试 schema 夹具更新正确。

索引元数据已加在合格字段上,能有效驱动相关生成与运行时测试路径。

Also applies to: 28-28

GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs (1)

270-312: 测试覆盖面完整,已覆盖索引元数据的正反两类路径。

这组新增测试同时验证了非法声明报错和合法声明生成行为,并校验非索引字段不会误生成索引结构。

Based on learnings "Source generator changes MUST be covered by generator tests" and "Regression fixes should include a test that fails before the fix and passes after it".

Also applies to: 314-362, 526-529, 568-574

Comment thread GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
- 实现 SchemaConfigGenerator 源代码生成器
- 支持从 JSON schema 文件生成配置类型和配置表包装类
- 生成强类型的 MonsterTable 配置表包装器
- 实现基于属性名称的查找索引构建功能
- 提供自动生成的 FindByName 和 TryFindFirstByName 方法
- 支持配置表的精确匹配查询操作
- 生成配置绑定辅助类和元数据常量
- 实现跨表引用关系的元数据提取功能
coderabbitai[bot]
coderabbitai Bot previously approved these changes Apr 8, 2026
@GeWuYou GeWuYou changed the title docs(config): 添加游戏内容配置系统完整文档 feat(config): 实现x-gframework-index索引元数据支持 Apr 8, 2026
@greptile-apps

greptile-apps Bot commented Apr 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR implements x-gframework-index boolean metadata support in the config schema system. Schema properties marked with this flag generate a lazy, thread-safe ReadOnlyDictionary index instead of a linear scan, routing FindBy* / TryFindFirstBy* helpers through the index while leaving the external API unchanged.

Key changes:

  • Validation (TryValidateIndexedLookupEligibility): enforces that indexed properties must be top-level, required, non-key, non-reference scalars; object and array types are additionally rejected inside their respective switch branches. A new GF_ConfigSchema_008 diagnostic is emitted on violations.
  • Code generation: adds per-indexed-property Build{Name}Index() delegates, a shared generic BuildLookupIndex<TProperty>() builder (with safe null-key skipping for malformed YAML data), and conditional null guards in the public helpers (emitted only for reference-type keys such as string).
  • Tests: four new unit tests cover metadata type enforcement, ineligible target rejection, dotted-key acceptance, and the null-key skip comment; integration tests and snapshot are updated accordingly.
  • Documentation (docs/zh-CN/game/config-system.md): extended to describe x-gframework-index usage constraints and the behavioral difference between indexed and linear-scan helpers.

Confidence Score: 4/5

Safe to merge after adding one missing XML <param> tag; all logic, threading, and null-safety aspects are correct.

The implementation is well-structured with thorough validation, thread-safe lazy initialization, correct null handling, good test coverage (unit + snapshot + integration), and updated documentation. The only finding is a missing <param name="isIndexedLookup"> entry in ParseArrayProperty's existing XML doc block — the same minor documentation gap that was resolved for TryValidateIndexedLookupEligibility in the prior review cycle. No logic bugs or security issues were found.

GFramework.SourceGenerators/Config/SchemaConfigGenerator.csParseArrayProperty XML doc is missing one <param> tag for the newly added parameter.

Vulnerabilities

No security concerns identified. The generator only reads JSON schema files supplied as AdditionalFiles (a controlled build input), performs no deserialization of untrusted user data at generator time, and the generated code does not expose any new public API that could be a vector for injection or data exposure. Lazy index initialization is properly guarded with LazyThreadSafetyMode.ExecutionAndPublication.

Important Files Changed

Filename Overview
GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs Core generator change: adds x-gframework-index parsing, eligibility validation, lazy index field generation, shared BuildLookupIndex<TProperty> helper, and FindBy*/TryFindFirstBy* routing through indexed or linear paths. Logic is sound; one missing <param> tag for the new isIndexedLookup argument added to ParseArrayProperty.
GFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.cs Adds GF_ConfigSchema_008 (InvalidLookupIndexMetadata) with well-formed message format matching the existing descriptor conventions.
GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.cs Adds four focused unit tests covering: non-boolean metadata rejection (GF_ConfigSchema_008), ineligible nested target rejection, dotted-key root property acceptance, and null-key skip behavior. Good coverage of the validation and generation paths.
GFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txt Snapshot updated correctly: adds _nameIndex lazy field, BuildNameIndex() delegate, shared generic BuildLookupIndex<TProperty>(), and index-routed FindByName/TryFindFirstByName. Null guard is only emitted for string (reference type), not for int (value type). Consistent with the new generation logic.
GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.cs Integration test updated to exercise indexed FindByName (unique), TryFindFirstByName, FindByFaction (multi-match) and TryFindFirstByFaction paths. Assertions correctly use Is.EqualTo for unique lookups and Is.EquivalentTo/Is.AnyOf for multi-match and order-independent cases.
GFramework.Game.Tests/schemas/monster.schema.json Adds x-gframework-index: true to both name and faction top-level required string properties, aligning the integration test schema with the new feature.
GFramework.SourceGenerators/AnalyzerReleases.Unshipped.md Correctly adds GF_ConfigSchema_008 to the unshipped release notes table in alphabetical order.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["ParseProperty()"] --> B{x-gframework-index present?}
    B -->|No| C[isIndexedLookup = false]
    B -->|Yes, not boolean| D["Emit GF_ConfigSchema_008\n(InvalidLookupIndexMetadata)"]
    B -->|Yes, boolean| E["TryValidateIndexedLookupEligibility()"]
    E -->|Not direct child of root| F["Emit GF_ConfigSchema_008\nLookupIndexTopLevelScalarOnlyMessage"]
    E -->|Not required| G["Emit GF_ConfigSchema_008\nLookupIndexRequiresRequiredScalarMessage"]
    E -->|Is primary key id| H["Emit GF_ConfigSchema_008\nLookupIndexPrimaryKeyMessage"]
    E -->|Has ref-table| I["Emit GF_ConfigSchema_008\nLookupIndexReferencePropertyMessage"]
    E -->|All checks pass| J[isIndexedLookup = true]
    J --> K{Schema type?}
    K -->|integer/number/boolean/string| L["SchemaPropertySpec (IsIndexedLookup=true)"]
    K -->|object| M["Emit GF_ConfigSchema_008\nLookupIndexTopLevelScalarOnlyMessage"]
    K -->|array| N["ParseArrayProperty - Emit GF_ConfigSchema_008"]
    C --> O{Schema type?}
    O --> P["SchemaPropertySpec (IsIndexedLookup=false)"]
    L --> Q["GenerateTableClass()"]
    P --> Q
    Q --> R{IsIndexedLookup?}
    R -->|Yes| S["Emit Lazy field + BuildXxxIndex() + shared BuildLookupIndex"]
    R -->|No| T["Emit linear scan FindBy*/TryFindFirstBy*"]
    S --> U["Emit index-routed FindBy*/TryFindFirstBy* with null guard for string"]
Loading

Reviews (2): Last reviewed commit: "feat(config): 添加配置架构生成器和怪物表自动生成" | Re-trigger Greptile

Comment thread GFramework.SourceGenerators/Config/SchemaConfigGenerator.cs
GeWuYou added 2 commits April 8, 2026 12:18
- 添加 isDirectChildOfRoot 参数的文档说明
- 实现 SchemaConfigGenerator 源代码生成器
- 自动生成 MonsterTable 配置表包装类
- 支持基于 JSON schema 的类型安全配置访问
- 生成配置表的精确匹配索引查找功能
- 实现懒加载的只读字典索引结构
- 添加配置实体的运行时注册和访问辅助方法
@greptile-apps

greptile-apps Bot commented Apr 8, 2026

Copy link
Copy Markdown

Tip:

Greploops — Automatically fix all review issues by running /greploops in Claude Code. It iterates: fix, push, re-review, repeat until 5/5 confidence.

Use the Greptile plugin for Claude Code to query reviews, search comments, and manage custom context directly from your terminal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant