github.com/hashicorp/hcl/v2@v2.20.0/ext/dynblock/unknown_body.go (about)

     1  // Copyright (c) HashiCorp, Inc.
     2  // SPDX-License-Identifier: MPL-2.0
     3  
     4  package dynblock
     5  
     6  import (
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/zclconf/go-cty/cty"
     9  )
    10  
    11  // unknownBody is a funny body that just reports everything inside it as
    12  // unknown. It uses a given other body as a sort of template for what attributes
    13  // and blocks are inside -- including source location information -- but
    14  // subsitutes unknown values of unknown type for all attributes.
    15  //
    16  // This rather odd process is used to handle expansion of dynamic blocks whose
    17  // for_each expression is unknown. Since a block cannot itself be unknown,
    18  // we instead arrange for everything _inside_ the block to be unknown instead,
    19  // to give the best possible approximation.
    20  type unknownBody struct {
    21  	template hcl.Body
    22  }
    23  
    24  var _ hcl.Body = unknownBody{}
    25  
    26  // hcldec.UnkownBody impl
    27  func (b unknownBody) Unknown() bool {
    28  	return true
    29  }
    30  
    31  func (b unknownBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
    32  	content, diags := b.template.Content(schema)
    33  	content = b.fixupContent(content)
    34  
    35  	// We're intentionally preserving the diagnostics reported from the
    36  	// inner body so that we can still report where the template body doesn't
    37  	// match the requested schema.
    38  	return content, diags
    39  }
    40  
    41  func (b unknownBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
    42  	content, remain, diags := b.template.PartialContent(schema)
    43  	content = b.fixupContent(content)
    44  	remain = unknownBody{remain} // remaining content must also be wrapped
    45  
    46  	// We're intentionally preserving the diagnostics reported from the
    47  	// inner body so that we can still report where the template body doesn't
    48  	// match the requested schema.
    49  	return content, remain, diags
    50  }
    51  
    52  func (b unknownBody) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
    53  	attrs, diags := b.template.JustAttributes()
    54  	attrs = b.fixupAttrs(attrs)
    55  
    56  	// We're intentionally preserving the diagnostics reported from the
    57  	// inner body so that we can still report where the template body doesn't
    58  	// match the requested schema.
    59  	return attrs, diags
    60  }
    61  
    62  func (b unknownBody) MissingItemRange() hcl.Range {
    63  	return b.template.MissingItemRange()
    64  }
    65  
    66  func (b unknownBody) fixupContent(got *hcl.BodyContent) *hcl.BodyContent {
    67  	ret := &hcl.BodyContent{}
    68  	ret.Attributes = b.fixupAttrs(got.Attributes)
    69  	if len(got.Blocks) > 0 {
    70  		ret.Blocks = make(hcl.Blocks, 0, len(got.Blocks))
    71  		for _, gotBlock := range got.Blocks {
    72  			new := *gotBlock                      // shallow copy
    73  			new.Body = unknownBody{gotBlock.Body} // nested content must also be marked unknown
    74  			ret.Blocks = append(ret.Blocks, &new)
    75  		}
    76  	}
    77  
    78  	return ret
    79  }
    80  
    81  func (b unknownBody) fixupAttrs(got hcl.Attributes) hcl.Attributes {
    82  	if len(got) == 0 {
    83  		return nil
    84  	}
    85  	ret := make(hcl.Attributes, len(got))
    86  	for name, gotAttr := range got {
    87  		new := *gotAttr // shallow copy
    88  		new.Expr = hcl.StaticExpr(cty.DynamicVal, gotAttr.Expr.Range())
    89  		ret[name] = &new
    90  	}
    91  	return ret
    92  }