package vm
import (
"fmt"
"strings"
"github.com/grafana/agent/pkg/river/ast"
"github.com/grafana/agent/pkg/river/diag"
"github.com/grafana/agent/pkg/river/internal/value"
"github.com/grafana/agent/pkg/river/printer"
"github.com/grafana/agent/pkg/river/token/builder"
)
func makeDiagnostic(err error, assoc map[value.Value]ast.Node) error {
var (
node ast.Node
expr strings.Builder
message string
cause value.Value
literal = false
)
isValueError := value.WalkError(err, func(err error) {
var val value.Value
switch ne := err.(type) {
case value.Error:
message = ne.Error()
val = ne.Value
case value.TypeError:
message = fmt.Sprintf("should be %s, got %s", ne.Expected, ne.Value.Type())
val = ne.Value
case value.MissingKeyError:
message = fmt.Sprintf("does not have field named %q", ne.Missing)
val = ne.Value
case value.ElementError:
fmt.Fprintf(&expr, "[%d]", ne.Index)
val = ne.Value
case value.FieldError:
fmt.Fprintf(&expr, ".%s", ne.Field)
val = ne.Value
}
cause = val
if foundNode, ok := assoc[val]; ok {
if literal {
expr.Reset()
}
node = foundNode
literal = true
} else {
literal = false
}
})
if !isValueError {
return err
}
if node != nil {
var nodeText strings.Builder
if err := printer.Fprint(&nodeText, node); err != nil {
panic(err)
}
message = fmt.Sprintf("%s%s %s", nodeText.String(), expr.String(), message)
} else {
message = fmt.Sprintf("%s %s", expr.String(), message)
}
var valueText string
if cause != value.Null {
be := builder.NewExpr()
be.SetValue(cause.Interface())
valueText = string(be.Bytes())
}
if literal {
valueText = ""
}
d := diag.Diagnostic{
Severity: diag.SeverityLevelError,
Message: message,
Value: valueText,
}
if node != nil {
d.StartPos = ast.StartPos(node).Position()
d.EndPos = ast.EndPos(node).Position()
}
return d
}