Global json adjustments
This commit is contained in:
@@ -972,6 +972,9 @@ func validateGlobalJSONFile(path string, obj map[string]any, report *ValidationR
|
||||
if _, ok := obj["overrides"]; ok {
|
||||
validateOverridesFile(path, obj, report)
|
||||
}
|
||||
if _, ok := obj["defaults"]; ok {
|
||||
validateGlobalDefaults(path, obj, report)
|
||||
}
|
||||
if rawPosition, ok := obj["position"]; ok {
|
||||
position, ok := rawPosition.(string)
|
||||
if !ok {
|
||||
@@ -1032,6 +1035,191 @@ func validateGlobalJSONFile(path string, obj map[string]any, report *ValidationR
|
||||
validateRowCollection(path, obj, rows, report)
|
||||
}
|
||||
|
||||
func topdataColumnsForGlobalValidation(path string, obj map[string]any) ([]string, bool) {
|
||||
basePath := filepath.Join(filepath.Dir(path), "base.json")
|
||||
baseData, err := loadJSONObject(basePath)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
datasetName := filepath.ToSlash(filepath.Base(filepath.Dir(path)))
|
||||
columns, err := parseColumns(baseData, datasetName)
|
||||
if err != nil {
|
||||
return nil, true
|
||||
}
|
||||
modulePaths, err := collectModulePaths(filepath.Join(filepath.Dir(path), "modules"))
|
||||
if err == nil {
|
||||
for _, modulePath := range modulePaths {
|
||||
moduleData, err := loadJSONObject(modulePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
columns, err = extendColumns(columns, moduleData, datasetName, modulePath)
|
||||
if err != nil {
|
||||
return columns, true
|
||||
}
|
||||
}
|
||||
}
|
||||
columns, err = extendColumns(columns, obj, datasetName, path)
|
||||
if err != nil {
|
||||
return columns, true
|
||||
}
|
||||
return columns, true
|
||||
}
|
||||
|
||||
func validateGlobalDefaults(path string, obj map[string]any, report *ValidationReport) {
|
||||
rawDefaults, ok := obj["defaults"]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
defaults, ok := rawDefaults.([]any)
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: "global defaults must be a JSON array",
|
||||
})
|
||||
return
|
||||
}
|
||||
columns, hasBaseDataset := topdataColumnsForGlobalValidation(path, obj)
|
||||
if !hasBaseDataset {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: "global defaults require a sibling base.json dataset",
|
||||
})
|
||||
return
|
||||
}
|
||||
for index, rawDefault := range defaults {
|
||||
defaultRule, ok := rawDefault.(map[string]any)
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d must be an object", index),
|
||||
})
|
||||
continue
|
||||
}
|
||||
validateGlobalDefaultMatch(path, index, defaultRule["match"], report)
|
||||
rawValues, ok := defaultRule["values"]
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values is required", index),
|
||||
})
|
||||
continue
|
||||
}
|
||||
values, ok := rawValues.(map[string]any)
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values must be an object", index),
|
||||
})
|
||||
continue
|
||||
}
|
||||
for field, value := range values {
|
||||
if _, ok := canonicalColumn(columns, field); !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values.%s is not a known column", index, field),
|
||||
})
|
||||
}
|
||||
validateGlobalDefaultValue(path, index, field, value, report)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func validateGlobalDefaultMatch(path string, index int, rawMatch any, report *ValidationReport) {
|
||||
if rawMatch == nil {
|
||||
return
|
||||
}
|
||||
if text, ok := rawMatch.(string); ok {
|
||||
if strings.EqualFold(strings.TrimSpace(text), "all") {
|
||||
return
|
||||
}
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d match must be all or an object", index),
|
||||
})
|
||||
return
|
||||
}
|
||||
match, ok := rawMatch.(map[string]any)
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d match must be all or an object", index),
|
||||
})
|
||||
return
|
||||
}
|
||||
for key := range match {
|
||||
if key != "source" {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d match.%s is not supported", index, key),
|
||||
})
|
||||
}
|
||||
}
|
||||
source, ok := match["source"].(string)
|
||||
if !ok || strings.TrimSpace(source) == "" {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d match.source is required", index),
|
||||
})
|
||||
return
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(source)) {
|
||||
case string(nativeRowSourceBase), string(nativeRowSourceEntries), string(nativeRowSourceOverride):
|
||||
default:
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d match.source is not supported", index),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func validateGlobalDefaultValue(path string, index int, field string, value any, report *ValidationReport) {
|
||||
obj, ok := value.(map[string]any)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
rawFormat, hasFormat := obj["format"]
|
||||
if !hasFormat {
|
||||
return
|
||||
}
|
||||
if len(obj) != 1 {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values.%s format object must contain only format", index, field),
|
||||
})
|
||||
return
|
||||
}
|
||||
format, ok := rawFormat.(string)
|
||||
if !ok {
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values.%s format must be a string", index, field),
|
||||
})
|
||||
return
|
||||
}
|
||||
if err := validateTopDataRowFormat(format); err != nil {
|
||||
message := strings.TrimPrefix(err.Error(), "default ")
|
||||
report.Diagnostics = append(report.Diagnostics, Diagnostic{
|
||||
Severity: SeverityError,
|
||||
Path: path,
|
||||
Message: fmt.Sprintf("global default %d values.%s %s", index, field, message),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func validateGlobalConditionList(path, label string, raw any, report *ValidationReport) {
|
||||
if raw == nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user