b3ea68948b
Go 1.19 will forecefully format all your doc strings. To get this out of the way, here is one big commit with all the changes gofmt wants to make.
254 lines
5.2 KiB
Go
254 lines
5.2 KiB
Go
package hclutil
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl/v2"
|
|
hcls "github.com/hashicorp/hcl/v2/hclsyntax"
|
|
)
|
|
|
|
// BlocksAsAttrs rewrites the hcl.Body so that hcl blocks are treated as
|
|
// attributes when schema is unknown.
|
|
//
|
|
// This conversion is necessary for parsing task driver configs, as they can be
|
|
// arbitrary nested without pre-defined schema.
|
|
//
|
|
// More concretely, it changes the following:
|
|
//
|
|
// ```
|
|
//
|
|
// config {
|
|
// meta { ... }
|
|
// }
|
|
//
|
|
// ```
|
|
//
|
|
// to
|
|
//
|
|
// ```
|
|
//
|
|
// config {
|
|
// meta = { ... } # <- attribute now
|
|
// }
|
|
//
|
|
// ```
|
|
func BlocksAsAttrs(body hcl.Body) hcl.Body {
|
|
if hclb, ok := body.(*hcls.Body); ok {
|
|
return &blockAttrs{body: hclb}
|
|
}
|
|
return body
|
|
}
|
|
|
|
type blockAttrs struct {
|
|
body hcl.Body
|
|
|
|
hiddenAttrs map[string]struct{}
|
|
hiddenBlocks map[string]struct{}
|
|
}
|
|
|
|
func (b *blockAttrs) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
|
|
bc, diags := b.body.Content(schema)
|
|
bc.Blocks = expandBlocks(bc.Blocks)
|
|
return bc, diags
|
|
}
|
|
func (b *blockAttrs) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
|
|
bc, remainBody, diags := b.body.PartialContent(schema)
|
|
bc.Blocks = expandBlocks(bc.Blocks)
|
|
|
|
remain := &blockAttrs{
|
|
body: remainBody,
|
|
hiddenAttrs: map[string]struct{}{},
|
|
hiddenBlocks: map[string]struct{}{},
|
|
}
|
|
for name := range b.hiddenAttrs {
|
|
remain.hiddenAttrs[name] = struct{}{}
|
|
}
|
|
for typeName := range b.hiddenBlocks {
|
|
remain.hiddenBlocks[typeName] = struct{}{}
|
|
}
|
|
for _, attrS := range schema.Attributes {
|
|
remain.hiddenAttrs[attrS.Name] = struct{}{}
|
|
}
|
|
for _, blockS := range schema.Blocks {
|
|
remain.hiddenBlocks[blockS.Type] = struct{}{}
|
|
}
|
|
|
|
return bc, remain, diags
|
|
}
|
|
|
|
func (b *blockAttrs) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
|
|
body, ok := b.body.(*hcls.Body)
|
|
if !ok {
|
|
return b.body.JustAttributes()
|
|
}
|
|
|
|
attrs := make(hcl.Attributes)
|
|
var diags hcl.Diagnostics
|
|
|
|
if body.Attributes == nil && len(body.Blocks) == 0 {
|
|
return attrs, diags
|
|
}
|
|
|
|
for name, attr := range body.Attributes {
|
|
if _, hidden := b.hiddenAttrs[name]; hidden {
|
|
continue
|
|
}
|
|
|
|
na := attr.AsHCLAttribute()
|
|
na.Expr = attrExpr(attr.Expr)
|
|
attrs[name] = na
|
|
}
|
|
|
|
for _, blocks := range blocksByType(body.Blocks) {
|
|
if _, hidden := b.hiddenBlocks[blocks[0].Type]; hidden {
|
|
continue
|
|
}
|
|
|
|
b := blocks[0]
|
|
attr := &hcls.Attribute{
|
|
Name: b.Type,
|
|
NameRange: b.TypeRange,
|
|
EqualsRange: b.OpenBraceRange,
|
|
SrcRange: b.Body.SrcRange,
|
|
Expr: blocksToExpr(blocks),
|
|
}
|
|
|
|
attrs[blocks[0].Type] = attr.AsHCLAttribute()
|
|
}
|
|
|
|
return attrs, diags
|
|
}
|
|
|
|
func (b *blockAttrs) MissingItemRange() hcl.Range {
|
|
return b.body.MissingItemRange()
|
|
}
|
|
|
|
func expandBlocks(blocks hcl.Blocks) hcl.Blocks {
|
|
if len(blocks) == 0 {
|
|
return blocks
|
|
}
|
|
|
|
r := make([]*hcl.Block, len(blocks))
|
|
for i, b := range blocks {
|
|
nb := *b
|
|
nb.Body = BlocksAsAttrs(b.Body)
|
|
r[i] = &nb
|
|
}
|
|
return r
|
|
}
|
|
|
|
func blocksByType(blocks hcls.Blocks) map[string]hcls.Blocks {
|
|
r := map[string]hcls.Blocks{}
|
|
for _, b := range blocks {
|
|
r[b.Type] = append(r[b.Type], b)
|
|
}
|
|
return r
|
|
}
|
|
|
|
func blocksToExpr(blocks hcls.Blocks) hcls.Expression {
|
|
if len(blocks) == 0 {
|
|
panic("unexpected empty blocks")
|
|
}
|
|
|
|
exprs := make([]hcls.Expression, len(blocks))
|
|
for i, b := range blocks {
|
|
exprs[i] = blockToExpr(b)
|
|
}
|
|
|
|
last := blocks[len(blocks)-1]
|
|
return &hcls.TupleConsExpr{
|
|
Exprs: exprs,
|
|
|
|
SrcRange: hcl.RangeBetween(blocks[0].OpenBraceRange, last.CloseBraceRange),
|
|
OpenRange: blocks[0].OpenBraceRange,
|
|
}
|
|
}
|
|
|
|
func blockToExpr(b *hcls.Block) hcls.Expression {
|
|
items := []hcls.ObjectConsItem{}
|
|
|
|
for _, attr := range b.Body.Attributes {
|
|
keyExpr := &hcls.ScopeTraversalExpr{
|
|
Traversal: hcl.Traversal{
|
|
hcl.TraverseRoot{
|
|
Name: attr.Name,
|
|
SrcRange: attr.NameRange,
|
|
},
|
|
},
|
|
SrcRange: attr.NameRange,
|
|
}
|
|
key := &hcls.ObjectConsKeyExpr{
|
|
Wrapped: keyExpr,
|
|
}
|
|
|
|
items = append(items, hcls.ObjectConsItem{
|
|
KeyExpr: key,
|
|
ValueExpr: attrExpr(attr.Expr),
|
|
})
|
|
}
|
|
|
|
for _, blocks := range blocksByType(b.Body.Blocks) {
|
|
keyExpr := &hcls.ScopeTraversalExpr{
|
|
Traversal: hcl.Traversal{
|
|
hcl.TraverseRoot{
|
|
Name: blocks[0].Type,
|
|
SrcRange: blocks[0].TypeRange,
|
|
},
|
|
},
|
|
SrcRange: blocks[0].TypeRange,
|
|
}
|
|
key := &hcls.ObjectConsKeyExpr{
|
|
Wrapped: keyExpr,
|
|
}
|
|
item := hcls.ObjectConsItem{
|
|
KeyExpr: key,
|
|
ValueExpr: blocksToExpr(blocks),
|
|
}
|
|
|
|
items = append(items, item)
|
|
}
|
|
|
|
v := &hcls.ObjectConsExpr{
|
|
Items: items,
|
|
}
|
|
|
|
// Create nested maps, with the labels as keys.
|
|
// Starts wrapping from most inner label to outer
|
|
for i := len(b.Labels) - 1; i >= 0; i-- {
|
|
keyExpr := &hcls.ScopeTraversalExpr{
|
|
Traversal: hcl.Traversal{
|
|
hcl.TraverseRoot{
|
|
Name: b.Labels[i],
|
|
SrcRange: b.LabelRanges[i],
|
|
},
|
|
},
|
|
SrcRange: b.LabelRanges[i],
|
|
}
|
|
key := &hcls.ObjectConsKeyExpr{
|
|
Wrapped: keyExpr,
|
|
}
|
|
item := hcls.ObjectConsItem{
|
|
KeyExpr: key,
|
|
ValueExpr: &hcls.TupleConsExpr{
|
|
Exprs: []hcls.Expression{v},
|
|
},
|
|
}
|
|
|
|
v = &hcls.ObjectConsExpr{
|
|
Items: []hcls.ObjectConsItem{item},
|
|
}
|
|
|
|
}
|
|
return v
|
|
}
|
|
|
|
func attrExpr(expr hcls.Expression) hcls.Expression {
|
|
if _, ok := expr.(*hcls.ObjectConsExpr); ok {
|
|
return &hcls.TupleConsExpr{
|
|
Exprs: []hcls.Expression{expr},
|
|
SrcRange: expr.Range(),
|
|
OpenRange: expr.StartRange(),
|
|
}
|
|
}
|
|
|
|
return expr
|
|
}
|