github.com/iaas-resource-provision/iaas-rpc@v1.0.7-0.20211021023331-ed21f798c408/internal/tfdiags/hcl.go (about)

     1  package tfdiags
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/hcl/v2"
     7  )
     8  
     9  // hclDiagnostic is a Diagnostic implementation that wraps a HCL Diagnostic
    10  type hclDiagnostic struct {
    11  	diag *hcl.Diagnostic
    12  }
    13  
    14  var _ Diagnostic = hclDiagnostic{}
    15  
    16  func (d hclDiagnostic) Severity() Severity {
    17  	switch d.diag.Severity {
    18  	case hcl.DiagWarning:
    19  		return Warning
    20  	default:
    21  		return Error
    22  	}
    23  }
    24  
    25  func (d hclDiagnostic) Description() Description {
    26  	return Description{
    27  		Summary: d.diag.Summary,
    28  		Detail:  d.diag.Detail,
    29  	}
    30  }
    31  
    32  func (d hclDiagnostic) Source() Source {
    33  	var ret Source
    34  	if d.diag.Subject != nil {
    35  		rng := SourceRangeFromHCL(*d.diag.Subject)
    36  		ret.Subject = &rng
    37  	}
    38  	if d.diag.Context != nil {
    39  		rng := SourceRangeFromHCL(*d.diag.Context)
    40  		ret.Context = &rng
    41  	}
    42  	return ret
    43  }
    44  
    45  func (d hclDiagnostic) FromExpr() *FromExpr {
    46  	if d.diag.Expression == nil || d.diag.EvalContext == nil {
    47  		return nil
    48  	}
    49  	return &FromExpr{
    50  		Expression:  d.diag.Expression,
    51  		EvalContext: d.diag.EvalContext,
    52  	}
    53  }
    54  
    55  // SourceRangeFromHCL constructs a SourceRange from the corresponding range
    56  // type within the HCL package.
    57  func SourceRangeFromHCL(hclRange hcl.Range) SourceRange {
    58  	return SourceRange{
    59  		Filename: hclRange.Filename,
    60  		Start: SourcePos{
    61  			Line:   hclRange.Start.Line,
    62  			Column: hclRange.Start.Column,
    63  			Byte:   hclRange.Start.Byte,
    64  		},
    65  		End: SourcePos{
    66  			Line:   hclRange.End.Line,
    67  			Column: hclRange.End.Column,
    68  			Byte:   hclRange.End.Byte,
    69  		},
    70  	}
    71  }
    72  
    73  // ToHCL constructs a HCL Range from the receiving SourceRange. This is the
    74  // opposite of SourceRangeFromHCL.
    75  func (r SourceRange) ToHCL() hcl.Range {
    76  	return hcl.Range{
    77  		Filename: r.Filename,
    78  		Start: hcl.Pos{
    79  			Line:   r.Start.Line,
    80  			Column: r.Start.Column,
    81  			Byte:   r.Start.Byte,
    82  		},
    83  		End: hcl.Pos{
    84  			Line:   r.End.Line,
    85  			Column: r.End.Column,
    86  			Byte:   r.End.Byte,
    87  		},
    88  	}
    89  }
    90  
    91  // ToHCL constructs a hcl.Diagnostics containing the same diagnostic messages
    92  // as the receiving tfdiags.Diagnostics.
    93  //
    94  // This conversion preserves the data that HCL diagnostics are able to
    95  // preserve but would be lossy in a round trip from tfdiags to HCL and then
    96  // back to tfdiags, because it will lose the specific type information of
    97  // the source diagnostics. In most cases this will not be a significant
    98  // problem, but could produce an awkward result in some special cases such
    99  // as converting the result of ConsolidateWarnings, which will force the
   100  // resulting warning groups to be flattened early.
   101  func (diags Diagnostics) ToHCL() hcl.Diagnostics {
   102  	if len(diags) == 0 {
   103  		return nil
   104  	}
   105  	ret := make(hcl.Diagnostics, len(diags))
   106  	for i, diag := range diags {
   107  		severity := diag.Severity()
   108  		desc := diag.Description()
   109  		source := diag.Source()
   110  		fromExpr := diag.FromExpr()
   111  
   112  		hclDiag := &hcl.Diagnostic{
   113  			Summary: desc.Summary,
   114  			Detail:  desc.Detail,
   115  		}
   116  
   117  		switch severity {
   118  		case Warning:
   119  			hclDiag.Severity = hcl.DiagWarning
   120  		case Error:
   121  			hclDiag.Severity = hcl.DiagError
   122  		default:
   123  			// The above should always be exhaustive for all of the valid
   124  			// Severity values in this package.
   125  			panic(fmt.Sprintf("unknown diagnostic severity %s", severity))
   126  		}
   127  		if source.Subject != nil {
   128  			hclDiag.Subject = source.Subject.ToHCL().Ptr()
   129  		}
   130  		if source.Context != nil {
   131  			hclDiag.Context = source.Context.ToHCL().Ptr()
   132  		}
   133  		if fromExpr != nil {
   134  			hclDiag.Expression = fromExpr.Expression
   135  			hclDiag.EvalContext = fromExpr.EvalContext
   136  		}
   137  
   138  		ret[i] = hclDiag
   139  	}
   140  	return ret
   141  }