github.com/hashicorp/hcl/v2@v2.20.0/ext/transform/error.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package transform
     5  
     6  import (
     7  	"github.com/hashicorp/hcl/v2"
     8  )
     9  
    10  // NewErrorBody returns a hcl.Body that returns the given diagnostics whenever
    11  // any of its content-access methods are called.
    12  //
    13  // The given diagnostics must have at least one diagnostic of severity
    14  // hcl.DiagError, or this function will panic.
    15  //
    16  // This can be used to prepare a return value for a Transformer that
    17  // can't complete due to an error. While the transform itself will succeed,
    18  // the error will be returned as soon as a caller attempts to extract content
    19  // from the resulting body.
    20  func NewErrorBody(diags hcl.Diagnostics) hcl.Body {
    21  	if !diags.HasErrors() {
    22  		panic("NewErrorBody called without any error diagnostics")
    23  	}
    24  	return diagBody{
    25  		Diags: diags,
    26  	}
    27  }
    28  
    29  // BodyWithDiagnostics returns a hcl.Body that wraps another hcl.Body
    30  // and emits the given diagnostics for any content-extraction method.
    31  //
    32  // Unlike the result of NewErrorBody, a body with diagnostics still runs
    33  // the extraction actions on the underlying body if (and only if) the given
    34  // diagnostics do not contain errors, but prepends the given diagnostics with
    35  // any diagnostics produced by the action.
    36  //
    37  // If the given diagnostics is empty, the given body is returned verbatim.
    38  //
    39  // This function is intended for conveniently reporting errors and/or warnings
    40  // produced during a transform, ensuring that they will be seen when the
    41  // caller eventually extracts content from the returned body.
    42  func BodyWithDiagnostics(body hcl.Body, diags hcl.Diagnostics) hcl.Body {
    43  	if len(diags) == 0 {
    44  		// nothing to do!
    45  		return body
    46  	}
    47  
    48  	return diagBody{
    49  		Diags:   diags,
    50  		Wrapped: body,
    51  	}
    52  }
    53  
    54  type diagBody struct {
    55  	Diags   hcl.Diagnostics
    56  	Wrapped hcl.Body
    57  }
    58  
    59  func (b diagBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
    60  	if b.Diags.HasErrors() {
    61  		return b.emptyContent(), b.Diags
    62  	}
    63  
    64  	content, wrappedDiags := b.Wrapped.Content(schema)
    65  	diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
    66  	diags = append(diags, b.Diags...)
    67  	diags = append(diags, wrappedDiags...)
    68  	return content, diags
    69  }
    70  
    71  func (b diagBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
    72  	if b.Diags.HasErrors() {
    73  		return b.emptyContent(), b.Wrapped, b.Diags
    74  	}
    75  
    76  	content, remain, wrappedDiags := b.Wrapped.PartialContent(schema)
    77  	diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
    78  	diags = append(diags, b.Diags...)
    79  	diags = append(diags, wrappedDiags...)
    80  	return content, remain, diags
    81  }
    82  
    83  func (b diagBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
    84  	if b.Diags.HasErrors() {
    85  		return nil, b.Diags
    86  	}
    87  
    88  	attributes, wrappedDiags := b.Wrapped.JustAttributes()
    89  	diags := make(hcl.Diagnostics, 0, len(b.Diags)+len(wrappedDiags))
    90  	diags = append(diags, b.Diags...)
    91  	diags = append(diags, wrappedDiags...)
    92  	return attributes, diags
    93  }
    94  
    95  func (b diagBody) MissingItemRange() hcl.Range {
    96  	if b.Wrapped != nil {
    97  		return b.Wrapped.MissingItemRange()
    98  	}
    99  
   100  	// Placeholder. This should never be seen in practice because decoding
   101  	// a diagBody without a wrapped body should always produce an error.
   102  	return hcl.Range{
   103  		Filename: "<empty>",
   104  	}
   105  }
   106  
   107  func (b diagBody) emptyContent() *hcl.BodyContent {
   108  	return &hcl.BodyContent{
   109  		MissingItemRange: b.MissingItemRange(),
   110  	}
   111  }