feat(config): 实现x-gframework-index索引元数据支持#195
Conversation
- 新增配置系统架构说明,涵盖 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 等错误诊断码 - 增加单元测试验证,确保消费者项目可以正常使用生成的聚合注册辅助和强类型访问入口
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
📜 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)
🧰 Additional context used📓 Path-based instructions (2)**/*.cs📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*SourceGenerators.Tests/**/*.cs📄 CodeRabbit inference engine (AGENTS.md)
Files:
🧠 Learnings (10)📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T10:00:34.101ZApplied to files:
📚 Learning: 2026-04-06T12:45:43.921ZApplied to files:
🔇 Additional comments (7)
📝 WalkthroughWalkthrough引入并解析 JSON Schema 元数据 Changes
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
|
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 ↗ |
Reviewer's Guide通过 生成配置表中索引查找解析的时序图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
生成配置表查找索引支持的类图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
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your Experience打开你的 dashboard 以:
Getting HelpOriginal review guide in EnglishReviewer's GuideAdd 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 tablesequenceDiagram
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
Class diagram for generated config table lookup index supportclassDiagram
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
}
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
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.帮我变得更有用!请在每条评论上点击 👍 或 👎,我会根据你的反馈改进后续的代码评审。
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.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
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*Tablehelper 又是每次访问都新建 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
📒 Files selected for processing (9)
GFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.Game.Tests/schemas/monster.schema.jsonGFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.csGFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.csGFramework.SourceGenerators.Tests/Config/snapshots/SchemaConfigGenerator/MonsterTable.g.txtGFramework.SourceGenerators/AnalyzerReleases.Unshipped.mdGFramework.SourceGenerators/Config/SchemaConfigGenerator.csGFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.csdocs/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 iin 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 requiredusingexplicitly
Write null-safe C# code that respects nullable annotations instead of suppressing warnings by default
Use the namespace patternGFramework.{Module}.{Feature}with PascalCase ...
Files:
GFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorSnapshotTests.csGFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.csGFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.csGFramework.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.csGFramework.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.csGFramework.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 relevantREADME.mdordocs/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.csGFramework.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.csGFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.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.csGFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.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.csGFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.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.csGFramework.SourceGenerators/Diagnostics/ConfigSchemaDiagnostics.csGFramework.Game.Tests/Config/GeneratedConfigConsumerIntegrationTests.csGFramework.SourceGenerators.Tests/Config/SchemaConfigGeneratorTests.csGFramework.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: 消费者集成测试样本与索引特性已一致。把
name和faction标记为索引字段后,现有断言可以真实覆盖生成查询辅助在消费者项目中的使用路径。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
- 实现 SchemaConfigGenerator 源代码生成器 - 支持从 JSON schema 文件生成配置类型和配置表包装类 - 生成强类型的 MonsterTable 配置表包装器 - 实现基于属性名称的查找索引构建功能 - 提供自动生成的 FindByName 和 TryFindFirstByName 方法 - 支持配置表的精确匹配查询操作 - 生成配置绑定辅助类和元数据常量 - 实现跨表引用关系的元数据提取功能
Greptile SummaryThis PR implements Key changes:
Confidence Score: 4/5Safe to merge after adding one missing XML 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
|
| 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"]
Reviews (2): Last reviewed commit: "feat(config): 添加配置架构生成器和怪物表自动生成" | Re-trigger Greptile
- 添加 isDirectChildOfRoot 参数的文档说明
- 实现 SchemaConfigGenerator 源代码生成器 - 自动生成 MonsterTable 配置表包装类 - 支持基于 JSON schema 的类型安全配置访问 - 生成配置表的精确匹配索引查找功能 - 实现懒加载的只读字典索引结构 - 添加配置实体的运行时注册和访问辅助方法
|
Tip: Greploops — Automatically fix all review issues by running Use the Greptile plugin for Claude Code to query reviews, search comments, and manage custom context directly from your terminal. |
Summary by Sourcery
在配置模式中添加对声明式索引查找的支持,包括在生成端进行校验、在生成的表中进行惰性索引构建,以及更新后的文档和测试。
新功能:
x-gframework-index(布尔值)在配置模式属性上声明一个生成的精确匹配查找索引。FindBy*/TryFindFirstBy*辅助方法。改进:
文档:
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:
Enhancements:
Documentation:
Tests:
Summary by CodeRabbit
新功能
文档
错误报告