fix(topdata): close invariant JSON roots
build-binaries / build-binaries (pull_request) Successful in 2m15s
test-image / build-image (pull_request) Successful in 37s
test / test (pull_request) Successful in 1m27s

This commit is contained in:
2026-06-25 23:10:39 +02:00
parent 14fd1c2b41
commit 75bfb9f042
4 changed files with 180 additions and 85 deletions
+7 -70
View File
@@ -532,6 +532,7 @@ func datasetInvariantForPath(dataPath topdataDataPath) (datasetValidationInvaria
}
func validateDatasetInvariantBaseFile(path string, obj map[string]any, invariant datasetValidationInvariant, report *ValidationReport) {
reportTopdataContractError(path, unsupportedObjectKeysError("base.json root", obj, baseOrPlainRootKeys...), report)
validateRowsFile(path, obj, report, true)
validateDerivedBaseOutput(path, obj, invariant.Name, report)
validateRequiredColumns(path, obj, invariant, report)
@@ -990,32 +991,6 @@ func validateOverridesFileWithColumns(path string, obj map[string]any, report *V
}
}
func parseGlobalConditionGroupsWithoutKeyCheck(injection map[string]any) (globalConditionGroups, error) {
var groups globalConditionGroups
if raw, ok := injection["require_present"]; ok {
parsed, err := parseGlobalConditionList("require_present", raw, false)
if err != nil {
return globalConditionGroups{}, err
}
groups.RequirePresent = parsed
}
if raw, ok := injection["any_present"]; ok {
parsed, err := parseGlobalConditionList("any_present", raw, true)
if err != nil {
return globalConditionGroups{}, err
}
groups.AnyPresent = parsed
}
if raw, ok := injection["unless_present"]; ok {
parsed, err := parseGlobalConditionList("unless_present", raw, false)
if err != nil {
return globalConditionGroups{}, err
}
groups.UnlessPresent = parsed
}
return groups, nil
}
func validateGlobalJSONFile(path string, obj map[string]any, report *ValidationReport) {
reportTopdataContractError(path, unsupportedObjectKeysError("global.json root", obj, globalRootKeys...), report)
if _, ok := obj["columns"]; ok {
@@ -1074,8 +1049,6 @@ func validateGlobalJSONFile(path string, obj map[string]any, report *ValidationR
})
continue
}
err := unsupportedObjectKeysError(fmt.Sprintf("global injection %d", index), injection, globalInjectionKeys...)
reportTopdataContractError(path, err, report)
row, ok := injection["row"].(map[string]any)
if !ok {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
@@ -1086,8 +1059,12 @@ func validateGlobalJSONFile(path string, obj map[string]any, report *ValidationR
} else {
rows = append(rows, row)
}
_, conditionErr := parseGlobalConditionGroupsWithoutKeyCheck(injection)
reportTopdataContractError(path, conditionErr, report)
_, _ = parseGlobalConditionGroups(injection, globalConditionParseOptions{
Label: fmt.Sprintf("global injection %d", index),
Report: func(err error) {
reportTopdataContractError(path, err, report)
},
})
}
validateRowCollection(path, obj, rows, report)
}
@@ -1269,46 +1246,6 @@ func validateGlobalDefaultValue(path string, index int, field string, value any,
}
}
func validateGlobalConditionList(path, label string, raw any, report *ValidationReport) {
if raw == nil {
return
}
conditions, ok := raw.([]any)
if !ok {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("%s must be a JSON array", label),
})
return
}
for index, rawCondition := range conditions {
condition, ok := rawCondition.(map[string]any)
if !ok {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("%s[%d] must be an object", label, index),
})
continue
}
if field, ok := condition["field"].(string); !ok || strings.TrimSpace(field) == "" {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("%s[%d].field is required", label, index),
})
}
if id, ok := condition["id"].(string); !ok || strings.TrimSpace(id) == "" {
report.Diagnostics = append(report.Diagnostics, Diagnostic{
Severity: SeverityError,
Path: path,
Message: fmt.Sprintf("%s[%d].id is required", label, index),
})
}
}
}
func validateStateObject(path string, obj map[string]any, report *ValidationReport) {
entries, ok := obj["entries"].(map[string]any)
if !ok {