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
|
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) {
|
func (c *featGeneratedContext) datasetRows(name string) (map[string]map[string]any, error) {
|
||||||
if rows, ok := c.rowsByDataset[name]; ok {
|
if rows, ok := c.rowsByDataset[name]; ok {
|
||||||
return rows, nil
|
return rows, nil
|
||||||
@@ -2555,7 +2567,10 @@ func buildFamilyExpansionGeneratedModule(path string, obj map[string]any, ctx *f
|
|||||||
if !include {
|
if !include {
|
||||||
continue
|
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)
|
featKey, rowID, hasID, err := ctx.resolveGeneratedFeatIdentity(spec, slug, row)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("generated feat file %s: %w", path, err)
|
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 {
|
if len(grants) == 0 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
skillRows, err := ctx.datasetRows("skills")
|
skillRows, err := ctx.datasetRows(ctx.skillsDatasetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -2854,7 +2869,7 @@ func (c *featGeneratedContext) displayNameForGeneratedSource(dataset string, row
|
|||||||
return text
|
return text
|
||||||
}
|
}
|
||||||
switch dataset {
|
switch dataset {
|
||||||
case "skills":
|
case c.skillsDatasetName():
|
||||||
return displayNameForSkill(row)
|
return displayNameForSkill(row)
|
||||||
case "baseitems":
|
case "baseitems":
|
||||||
return displayNameForBaseitem(row)
|
return displayNameForBaseitem(row)
|
||||||
|
|||||||
@@ -1867,8 +1867,10 @@ func validateGeneratedFeatFamilies(dataDir string, report *ValidationReport) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
required := []requiredFeatFamily{
|
required := []requiredFeatFamily{
|
||||||
{FamilyKey: "skillfocus", Dataset: "skills", Predicate: "accessible"},
|
// skill families: the source dataset is data-driven (family spec), only
|
||||||
{FamilyKey: "greaterskillfocus", Dataset: "skills", Predicate: "accessible"},
|
// the accessibility predicate is required
|
||||||
|
{FamilyKey: "skillfocus", Predicate: "accessible"},
|
||||||
|
{FamilyKey: "greaterskillfocus", Predicate: "accessible"},
|
||||||
{FamilyKey: "weaponfocus", Dataset: "baseitems", Column: "WeaponFocusFeat"},
|
{FamilyKey: "weaponfocus", Dataset: "baseitems", Column: "WeaponFocusFeat"},
|
||||||
{FamilyKey: "weaponspecialization", Dataset: "baseitems", Column: "WeaponSpecializationFeat"},
|
{FamilyKey: "weaponspecialization", Dataset: "baseitems", Column: "WeaponSpecializationFeat"},
|
||||||
{FamilyKey: "improvedcritical", Dataset: "baseitems", Column: "WeaponImprovedCriticalFeat"},
|
{FamilyKey: "improvedcritical", Dataset: "baseitems", Column: "WeaponImprovedCriticalFeat"},
|
||||||
@@ -1882,7 +1884,7 @@ func validateGeneratedFeatFamilies(dataDir string, report *ValidationReport) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if spec.ChildSource.Dataset != requirement.Dataset ||
|
if (requirement.Dataset != "" && spec.ChildSource.Dataset != requirement.Dataset) ||
|
||||||
spec.ChildSource.Column != requirement.Column ||
|
spec.ChildSource.Column != requirement.Column ||
|
||||||
spec.ChildSource.Predicate != requirement.Predicate {
|
spec.ChildSource.Predicate != requirement.Predicate {
|
||||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||||
@@ -2081,7 +2083,10 @@ func validateGeneratedFeatFamilyCompleteness(path string, spec familyExpansionSp
|
|||||||
}
|
}
|
||||||
if include {
|
if include {
|
||||||
if familyAllowlist {
|
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)
|
featKey, _, _, err := ctx.resolveGeneratedFeatIdentity(spec, slug, row)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||||
|
|||||||
@@ -569,11 +569,13 @@ func loadWikiContext(dataDir, sourceDir string) (*wikiContext, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
loadBase := func(name string) (nativeCollectedDataset, bool, error) {
|
loadBase := func(names ...string) (nativeCollectedDataset, bool, error) {
|
||||||
for _, dataset := range datasets {
|
for _, name := range names {
|
||||||
if dataset.Name == name {
|
for _, dataset := range datasets {
|
||||||
collected, err := collectNativeDataset(dataset)
|
if dataset.Name == name {
|
||||||
return collected, true, err
|
collected, err := collectNativeDataset(dataset)
|
||||||
|
return collected, true, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nativeCollectedDataset{}, false, nil
|
return nativeCollectedDataset{}, false, nil
|
||||||
@@ -583,7 +585,7 @@ func loadWikiContext(dataDir, sourceDir string) (*wikiContext, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
skillDataset, skillOK, err := loadBase("skills")
|
skillDataset, skillOK, err := loadBase("skills", "skills/core")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user