Files
notarius/internal/modules/dnd/shared/diagnostics/diagnostics.go

79 lines
2.1 KiB
Go

// Package diagnostics provides bounded, safe text for deterministic D&D
// decisions and warnings.
package diagnostics
import (
"fmt"
"strconv"
"strings"
"gitea.maximumdirect.net/eric/notarius/internal/framework/contracts"
)
const (
MaxIssues = 20
MaxWarnings = 20
MaxDisplayedRunes = 128
MaxMessageBytes = 4096
)
func Truncate(value string) string {
runes := []rune(value)
if len(runes) <= MaxDisplayedRunes {
return value
}
return string(runes[:MaxDisplayedRunes-1]) + "…"
}
func Quote(value string) string { return strconv.Quote(Truncate(value)) }
func Aggregate(prefix string, issues []string) string {
displayed := make([]string, 0, min(len(issues), MaxIssues))
for len(displayed) < len(issues) && len(displayed) < MaxIssues {
issue := Truncate(issues[len(displayed)])
candidate := aggregateMessage(prefix, append(displayed, issue), len(issues)-len(displayed)-1)
if len([]byte(candidate)) > MaxMessageBytes {
break
}
displayed = append(displayed, issue)
}
return aggregateMessage(prefix, displayed, len(issues)-len(displayed))
}
// LimitWarnings returns at most MaxWarnings warnings, reserving the final
// position for a deterministic omission summary when truncation is required.
func LimitWarnings(warnings []contracts.Warning, scope, reasonCode string) []contracts.Warning {
if warnings == nil {
return nil
}
if len(warnings) <= MaxWarnings {
bounded := make([]contracts.Warning, len(warnings))
copy(bounded, warnings)
return bounded
}
displayed := MaxWarnings - 1
bounded := make([]contracts.Warning, displayed, MaxWarnings)
copy(bounded, warnings[:displayed])
bounded = append(bounded, contracts.Warning{
Scope: scope,
ReasonCode: reasonCode,
Message: fmt.Sprintf("%d additional warning(s) omitted", len(warnings)-displayed),
})
return bounded
}
func aggregateMessage(prefix string, issues []string, omitted int) string {
message := prefix + ": " + strings.Join(issues, ", ")
if omitted > 0 {
message += fmt.Sprintf("; %d additional issue(s) omitted", omitted)
}
return message
}
func min(left, right int) int {
if left < right {
return left
}
return right
}