topdata: stop hardcoding the skills dataset location (#43)
sow-topdata moved skills into a tree (skills/core, skills/specs, skillcats, skillspecranks), which broke validate/build: the generated feat families hardcoded dataset "skills". Resolution is now data-driven: the family spec's child_source names the dataset, child slugs come from the row key's own namespace, and the wiki loader accepts both the flat and tree layouts (topdata main still uses the flat one until the overhaul merges). Verified against the skill-grouping-overhaul topdata branch: validate/build/wiki all clean with zero lock churn, focus feats stay on their adopted rows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Reviewed-on: #43 Co-authored-by: vickydotbat <vickydotbat@tutamail.com> Co-committed-by: vickydotbat <vickydotbat@tutamail.com>
This commit is contained in:
@@ -2317,6 +2317,18 @@ func (c *featGeneratedContext) familyHasExistingRows(familyKey string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// skillsDatasetName returns the dataset the skill_focus family sources its
|
||||
// children from. The skills dataset location is data-driven via that spec;
|
||||
// "skills" is only the fallback when no spec is loaded.
|
||||
func (c *featGeneratedContext) skillsDatasetName() string {
|
||||
for key, spec := range c.familySpecs {
|
||||
if normalizeKeyIdentity(key) == "skillfocus" && spec.ChildSource.Dataset != "" {
|
||||
return spec.ChildSource.Dataset
|
||||
}
|
||||
}
|
||||
return "skills"
|
||||
}
|
||||
|
||||
func (c *featGeneratedContext) datasetRows(name string) (map[string]map[string]any, error) {
|
||||
if rows, ok := c.rowsByDataset[name]; ok {
|
||||
return rows, nil
|
||||
@@ -2555,7 +2567,10 @@ func buildFamilyExpansionGeneratedModule(path string, obj map[string]any, ctx *f
|
||||
if !include {
|
||||
continue
|
||||
}
|
||||
slug := strings.TrimPrefix(sourceKey, spec.ChildSource.Dataset+":")
|
||||
slug := sourceKey
|
||||
if idx := strings.Index(slug, ":"); idx >= 0 {
|
||||
slug = slug[idx+1:]
|
||||
}
|
||||
featKey, rowID, hasID, err := ctx.resolveGeneratedFeatIdentity(spec, slug, row)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("generated feat file %s: %w", path, err)
|
||||
@@ -2655,7 +2670,7 @@ func buildRacialtypesSkillAffinityModule(ctx *featGeneratedContext) (map[string]
|
||||
if len(grants) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
skillRows, err := ctx.datasetRows("skills")
|
||||
skillRows, err := ctx.datasetRows(ctx.skillsDatasetName())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -2854,7 +2869,7 @@ func (c *featGeneratedContext) displayNameForGeneratedSource(dataset string, row
|
||||
return text
|
||||
}
|
||||
switch dataset {
|
||||
case "skills":
|
||||
case c.skillsDatasetName():
|
||||
return displayNameForSkill(row)
|
||||
case "baseitems":
|
||||
return displayNameForBaseitem(row)
|
||||
|
||||
@@ -1867,8 +1867,10 @@ func validateGeneratedFeatFamilies(dataDir string, report *ValidationReport) {
|
||||
}
|
||||
|
||||
required := []requiredFeatFamily{
|
||||
{FamilyKey: "skillfocus", Dataset: "skills", Predicate: "accessible"},
|
||||
{FamilyKey: "greaterskillfocus", Dataset: "skills", Predicate: "accessible"},
|
||||
// skill families: the source dataset is data-driven (family spec), only
|
||||
// the accessibility predicate is required
|
||||
{FamilyKey: "skillfocus", Predicate: "accessible"},
|
||||
{FamilyKey: "greaterskillfocus", Predicate: "accessible"},
|
||||
{FamilyKey: "weaponfocus", Dataset: "baseitems", Column: "WeaponFocusFeat"},
|
||||
{FamilyKey: "weaponspecialization", Dataset: "baseitems", Column: "WeaponSpecializationFeat"},
|
||||
{FamilyKey: "improvedcritical", Dataset: "baseitems", Column: "WeaponImprovedCriticalFeat"},
|
||||
@@ -1882,7 +1884,7 @@ func validateGeneratedFeatFamilies(dataDir string, report *ValidationReport) {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if spec.ChildSource.Dataset != requirement.Dataset ||
|
||||
if (requirement.Dataset != "" && spec.ChildSource.Dataset != requirement.Dataset) ||
|
||||
spec.ChildSource.Column != requirement.Column ||
|
||||
spec.ChildSource.Predicate != requirement.Predicate {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
@@ -2081,7 +2083,10 @@ func validateGeneratedFeatFamilyCompleteness(path string, spec familyExpansionSp
|
||||
}
|
||||
if include {
|
||||
if familyAllowlist {
|
||||
slug := strings.TrimPrefix(sourceKey, spec.ChildSource.Dataset+":")
|
||||
slug := sourceKey
|
||||
if idx := strings.Index(slug, ":"); idx >= 0 {
|
||||
slug = slug[idx+1:]
|
||||
}
|
||||
featKey, _, _, err := ctx.resolveGeneratedFeatIdentity(spec, slug, row)
|
||||
if err != nil {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
|
||||
@@ -569,11 +569,13 @@ func loadWikiContext(dataDir, sourceDir string) (*wikiContext, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
loadBase := func(name string) (nativeCollectedDataset, bool, error) {
|
||||
for _, dataset := range datasets {
|
||||
if dataset.Name == name {
|
||||
collected, err := collectNativeDataset(dataset)
|
||||
return collected, true, err
|
||||
loadBase := func(names ...string) (nativeCollectedDataset, bool, error) {
|
||||
for _, name := range names {
|
||||
for _, dataset := range datasets {
|
||||
if dataset.Name == name {
|
||||
collected, err := collectNativeDataset(dataset)
|
||||
return collected, true, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nativeCollectedDataset{}, false, nil
|
||||
@@ -583,7 +585,7 @@ func loadWikiContext(dataDir, sourceDir string) (*wikiContext, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
skillDataset, skillOK, err := loadBase("skills")
|
||||
skillDataset, skillOK, err := loadBase("skills", "skills/core")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user