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 }