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