hcl/ext/transform/error.go
Martin Atkins 6c4344623b Unfold the "hcl" directory up into the root
The main HCL package is more visible this way, and so it's easier than
having to pick it out from dozens of other package directories.
2019-09-09 16:08:19 -07:00

109 lines
3.2 KiB
Go

package transform
import (
"github.com/hashicorp/hcl/v2"
)
// NewErrorBody returns a hcl.Body that returns the given diagnostics whenever
// any of its content-access methods are called.
//
// The given diagnostics must have at least one diagnostic of severity
// hcl.DiagError, or this function will panic.
//
// This can be used to prepare a return value for a Transformer that
// can't complete due to an error. While the transform itself will succeed,
// the error will be returned as soon as a caller attempts to extract content
// from the resulting body.
func NewErrorBody(diags hcl.Diagnostics) hcl.Body {
if !diags.HasErrors() {
panic("NewErrorBody called without any error diagnostics")
}
return diagBody{
Diags: diags,
}
}
// BodyWithDiagnostics returns a hcl.Body that wraps another hcl.Body
// and emits the given diagnostics for any content-extraction method.
//
// Unlike the result of NewErrorBody, a body with diagnostics still runs
// the extraction actions on the underlying body if (and only if) the given
// diagnostics do not contain errors, but prepends the given diagnostics with
// any diagnostics produced by the action.
//
// If the given diagnostics is empty, the given body is returned verbatim.
//
// This function is intended for conveniently reporting errors and/or warnings
// produced during a transform, ensuring that they will be seen when the
// caller eventually extracts content from the returned body.
func BodyWithDiagnostics(body hcl.Body, diags hcl.Diagnostics) hcl.Body {
if len(diags) == 0 {
// nothing to do!
return body
}
return diagBody{
Diags: diags,
Wrapped: body,
}
}
type diagBody struct {
Diags hcl.Diagnostics
Wrapped hcl.Body
}
func (b diagBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
if b.Diags.HasErrors() {
return b.emptyContent(), b.Diags
}
content, wrappedDiags := b.Wrapped.Content(schema)
diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
diags = append(diags, b.Diags...)
diags = append(diags, wrappedDiags...)
return content, diags
}
func (b diagBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
if b.Diags.HasErrors() {
return b.emptyContent(), b.Wrapped, b.Diags
}
content, remain, wrappedDiags := b.Wrapped.PartialContent(schema)
diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
diags = append(diags, b.Diags...)
diags = append(diags, wrappedDiags...)
return content, remain, diags
}
func (b diagBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
if b.Diags.HasErrors() {
return nil, b.Diags
}
attributes, wrappedDiags := b.Wrapped.JustAttributes()
diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
diags = append(diags, b.Diags...)
diags = append(diags, wrappedDiags...)
return attributes, diags
}
func (b diagBody) MissingItemRange() hcl.Range {
if b.Wrapped != nil {
return b.Wrapped.MissingItemRange()
}
// Placeholder. This should never be seen in practice because decoding
// a diagBody without a wrapped body should always produce an error.
return hcl.Range{
Filename: "<empty>",
}
}
func (b diagBody) emptyContent() *hcl.BodyContent {
return &hcl.BodyContent{
MissingItemRange: b.MissingItemRange(),
}
}