Error on duplicate keys

This commit is contained in:
2026-05-15 23:02:33 +02:00
parent 505afb5ac5
commit 28bea40038
2 changed files with 92 additions and 0 deletions
+59
View File
@@ -264,6 +264,7 @@ func ValidateProject(p *project.Project) ValidationReport {
}) })
validateTopPackageAssets(sourceDir, dataDir, &report) validateTopPackageAssets(sourceDir, dataDir, &report)
validateNativeOutputCatalog(dataDir, &report) validateNativeOutputCatalog(dataDir, &report)
validateNativeEntryKeyUniqueness(dataDir, &report)
validateNativeLockAllocation(dataDir, &report) validateNativeLockAllocation(dataDir, &report)
validateGeneratedFeatFamilies(dataDir, &report) validateGeneratedFeatFamilies(dataDir, &report)
validateItempropsRegistryGraph(dataDir, &report) validateItempropsRegistryGraph(dataDir, &report)
@@ -1001,6 +1002,64 @@ func validateNativeOutputCatalog(dataDir string, report *ValidationReport) {
} }
} }
func validateNativeEntryKeyUniqueness(dataDir string, report *ValidationReport) {
datasets, err := discoverNativeDatasets(dataDir)
if err != nil {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: dataDir,
Message: fmt.Sprintf("discover native datasets for entry key uniqueness validation: %v", err),
})
return
}
for _, dataset := range datasets {
if dataset.Kind != nativeDatasetBase {
continue
}
entryKeyPath := map[string]string{}
for _, dir := range []string{dataset.ModulesDir, dataset.GeneratedDir} {
paths, err := collectModulePaths(dir)
if err != nil {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: dir,
Message: fmt.Sprintf("collect module paths for entry key uniqueness validation: %v", err),
})
continue
}
for _, path := range paths {
obj, err := loadJSONObject(path)
if err != nil {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("load module for entry key uniqueness validation: %v", err),
})
continue
}
entries, ok := obj["entries"].(map[string]any)
if !ok {
continue
}
for _, key := range sortedKeys(entries) {
if key == "" {
continue
}
if previousPath, exists := entryKeyPath[key]; exists {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("duplicate entries key %q declared by %s and %s", key, previousPath, path),
})
continue
}
entryKeyPath[key] = path
}
}
}
}
}
func validateNativeLockAllocation(dataDir string, report *ValidationReport) { func validateNativeLockAllocation(dataDir string, report *ValidationReport) {
datasets, err := discoverNativeDatasets(dataDir) datasets, err := discoverNativeDatasets(dataDir)
if err != nil { if err != nil {
+33
View File
@@ -134,6 +134,39 @@ func TestValidateProjectRejectsDuplicateJSONKeys(t *testing.T) {
} }
} }
func TestValidateProjectRejectsDuplicateEntryKeysAcrossModules(t *testing.T) {
root := testProjectRoot(t)
mkdirAll(t, filepath.Join(root, "topdata", "data", "baseitems", "modules"))
writeFile(t, filepath.Join(root, "topdata", "base_dialog.json"), "{}\n")
writeFile(t, filepath.Join(root, "topdata", "data", "baseitems", "base.json"), `{
"output": "baseitems.2da",
"columns": ["Label", "MaxRange"],
"rows": []
}`+"\n")
writeFile(t, filepath.Join(root, "topdata", "data", "baseitems", "lock.json"), "{}\n")
writeFile(t, filepath.Join(root, "topdata", "data", "baseitems", "modules", "10_add_sign.json"), `{
"entries": {
"baseitems:holdable_sign": {"Label": "Holdable Sign", "MaxRange": "100"}
}
}`+"\n")
writeFile(t, filepath.Join(root, "topdata", "data", "baseitems", "modules", "20_add_sign_again.json"), `{
"entries": {
"baseitems:holdable_sign": {"Label": "Duplicate Sign", "MaxRange": "200"}
}
}`+"\n")
report := ValidateProject(testProject(root))
if !report.HasErrors() {
t.Fatal("expected duplicate entry key validation error")
}
text := diagnosticsText(report.Diagnostics)
if !strings.Contains(text, `duplicate entries key "baseitems:holdable_sign"`) ||
!strings.Contains(text, "10_add_sign.json") ||
!strings.Contains(text, "20_add_sign_again.json") {
t.Fatalf("expected duplicate entry key diagnostic with both module paths, got:\n%s", text)
}
}
func TestResolvedTableRegistryRegistersConsistentTables(t *testing.T) { func TestResolvedTableRegistryRegistersConsistentTables(t *testing.T) {
collected := []nativeCollectedDataset{ collected := []nativeCollectedDataset{
{ {