d754d5a269
Although our underlying parse tree retains all of the token content, it doesn't necessarily retain all of the spacing information under editing, and so formatting on save ensures that we'll produce a canonical result even if some edits have been applied that have changed the expected alignment of objects, etc.
134 lines
3.1 KiB
Go
134 lines
3.1 KiB
Go
package hclwrite
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl2/hcl"
|
|
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
type Body struct {
|
|
inTree
|
|
|
|
items nodeSet
|
|
}
|
|
|
|
func (b *Body) appendItem(c nodeContent) *node {
|
|
nn := b.children.Append(c)
|
|
b.items.Add(nn)
|
|
return nn
|
|
}
|
|
|
|
func (b *Body) appendItemNode(nn *node) *node {
|
|
nn.assertUnattached()
|
|
b.children.AppendNode(nn)
|
|
b.items.Add(nn)
|
|
return nn
|
|
}
|
|
|
|
func (b *Body) AppendUnstructuredTokens(ts Tokens) {
|
|
b.inTree.children.Append(ts)
|
|
}
|
|
|
|
// GetAttribute returns the attribute from the body that has the given name,
|
|
// or returns nil if there is currently no matching attribute.
|
|
func (b *Body) GetAttribute(name string) *Attribute {
|
|
for n := range b.items {
|
|
if attr, isAttr := n.content.(*Attribute); isAttr {
|
|
nameObj := attr.name.content.(*identifier)
|
|
if nameObj.hasName(name) {
|
|
// We've found it!
|
|
return attr
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// SetAttributeValue either replaces the expression of an existing attribute
|
|
// of the given name or adds a new attribute definition to the end of the block.
|
|
//
|
|
// The value is given as a cty.Value, and must therefore be a literal. To set
|
|
// a variable reference or other traversal, use SetAttributeTraversal.
|
|
//
|
|
// The return value is the attribute that was either modified in-place or
|
|
// created.
|
|
func (b *Body) SetAttributeValue(name string, val cty.Value) *Attribute {
|
|
attr := b.GetAttribute(name)
|
|
expr := NewExpressionLiteral(val)
|
|
if attr != nil {
|
|
attr.expr = attr.expr.ReplaceWith(expr)
|
|
} else {
|
|
attr := newAttribute()
|
|
attr.init(name, expr)
|
|
b.appendItem(attr)
|
|
}
|
|
return attr
|
|
}
|
|
|
|
// SetAttributeTraversal either replaces the expression of an existing attribute
|
|
// of the given name or adds a new attribute definition to the end of the block.
|
|
//
|
|
// The new expression is given as a hcl.Traversal, which must be an absolute
|
|
// traversal. To set a literal value, use SetAttributeValue.
|
|
//
|
|
// The return value is the attribute that was either modified in-place or
|
|
// created.
|
|
func (b *Body) SetAttributeTraversal(name string, traversal hcl.Traversal) *Attribute {
|
|
panic("Body.SetAttributeTraversal not yet implemented")
|
|
}
|
|
|
|
type Attribute struct {
|
|
inTree
|
|
|
|
leadComments *node
|
|
name *node
|
|
expr *node
|
|
lineComments *node
|
|
}
|
|
|
|
func newAttribute() *Attribute {
|
|
return &Attribute{
|
|
inTree: newInTree(),
|
|
}
|
|
}
|
|
|
|
func (a *Attribute) init(name string, expr *Expression) {
|
|
expr.assertUnattached()
|
|
|
|
nameTok := newIdentToken(name)
|
|
nameObj := newIdentifier(nameTok)
|
|
a.leadComments = a.children.Append(newComments(nil))
|
|
a.name = a.children.Append(nameObj)
|
|
a.children.AppendUnstructuredTokens(Tokens{
|
|
{
|
|
Type: hclsyntax.TokenEqual,
|
|
Bytes: []byte{'='},
|
|
},
|
|
})
|
|
a.expr = a.children.Append(expr)
|
|
a.expr.list = a.children
|
|
a.lineComments = a.children.Append(newComments(nil))
|
|
a.children.AppendUnstructuredTokens(Tokens{
|
|
{
|
|
Type: hclsyntax.TokenNewline,
|
|
Bytes: []byte{'\n'},
|
|
},
|
|
})
|
|
}
|
|
|
|
func (a *Attribute) Expr() *Expression {
|
|
return a.expr.content.(*Expression)
|
|
}
|
|
|
|
type Block struct {
|
|
inTree
|
|
|
|
leadComments *node
|
|
typeName *node
|
|
labels nodeSet
|
|
open *node
|
|
body *node
|
|
close *node
|
|
}
|