opentofu/internal/tfdiags/hcl.go
Martin Atkins 05caff2ca3 Move tfdiags/ to internal/tfdiags/
This is part of a general effort to move all of Terraform's non-library
package surface under internal in order to reinforce that these are for
internal use within Terraform only.

If you were previously importing packages under this prefix into an
external codebase, you could pin to an earlier release tag as an interim
solution until you've make a plan to achieve the same functionality some
other way.
2021-05-17 14:09:07 -07:00

142 lines
3.4 KiB
Go

package tfdiags
import (
"fmt"
"github.com/hashicorp/hcl/v2"
)
// hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
type hclDiagnostic struct {
diag *hcl.Diagnostic
}
var _ Diagnostic = hclDiagnostic{}
func (d hclDiagnostic) Severity() Severity {
switch d.diag.Severity {
case hcl.DiagWarning:
return Warning
default:
return Error
}
}
func (d hclDiagnostic) Description() Description {
return Description{
Summary: d.diag.Summary,
Detail: d.diag.Detail,
}
}
func (d hclDiagnostic) Source() Source {
var ret Source
if d.diag.Subject != nil {
rng := SourceRangeFromHCL(*d.diag.Subject)
ret.Subject = &rng
}
if d.diag.Context != nil {
rng := SourceRangeFromHCL(*d.diag.Context)
ret.Context = &rng
}
return ret
}
func (d hclDiagnostic) FromExpr() *FromExpr {
if d.diag.Expression == nil || d.diag.EvalContext == nil {
return nil
}
return &FromExpr{
Expression: d.diag.Expression,
EvalContext: d.diag.EvalContext,
}
}
// SourceRangeFromHCL constructs a SourceRange from the corresponding range
// type within the HCL package.
func SourceRangeFromHCL(hclRange hcl.Range) SourceRange {
return SourceRange{
Filename: hclRange.Filename,
Start: SourcePos{
Line: hclRange.Start.Line,
Column: hclRange.Start.Column,
Byte: hclRange.Start.Byte,
},
End: SourcePos{
Line: hclRange.End.Line,
Column: hclRange.End.Column,
Byte: hclRange.End.Byte,
},
}
}
// ToHCL constructs a HCL Range from the receiving SourceRange. This is the
// opposite of SourceRangeFromHCL.
func (r SourceRange) ToHCL() hcl.Range {
return hcl.Range{
Filename: r.Filename,
Start: hcl.Pos{
Line: r.Start.Line,
Column: r.Start.Column,
Byte: r.Start.Byte,
},
End: hcl.Pos{
Line: r.End.Line,
Column: r.End.Column,
Byte: r.End.Byte,
},
}
}
// ToHCL constructs a hcl.Diagnostics containing the same diagnostic messages
// as the receiving tfdiags.Diagnostics.
//
// This conversion preserves the data that HCL diagnostics are able to
// preserve but would be lossy in a round trip from tfdiags to HCL and then
// back to tfdiags, because it will lose the specific type information of
// the source diagnostics. In most cases this will not be a significant
// problem, but could produce an awkward result in some special cases such
// as converting the result of ConsolidateWarnings, which will force the
// resulting warning groups to be flattened early.
func (diags Diagnostics) ToHCL() hcl.Diagnostics {
if len(diags) == 0 {
return nil
}
ret := make(hcl.Diagnostics, len(diags))
for i, diag := range diags {
severity := diag.Severity()
desc := diag.Description()
source := diag.Source()
fromExpr := diag.FromExpr()
hclDiag := &hcl.Diagnostic{
Summary: desc.Summary,
Detail: desc.Detail,
}
switch severity {
case Warning:
hclDiag.Severity = hcl.DiagWarning
case Error:
hclDiag.Severity = hcl.DiagError
default:
// The above should always be exhaustive for all of the valid
// Severity values in this package.
panic(fmt.Sprintf("unknown diagnostic severity %s", severity))
}
if source.Subject != nil {
hclDiag.Subject = source.Subject.ToHCL().Ptr()
}
if source.Context != nil {
hclDiag.Context = source.Context.ToHCL().Ptr()
}
if fromExpr != nil {
hclDiag.Expression = fromExpr.Expression
hclDiag.EvalContext = fromExpr.EvalContext
}
ret[i] = hclDiag
}
return ret
}