hcl2: github.com/hashicorp/hcl2/hclwrite Index | Examples | Files

package hclwrite

import "github.com/hashicorp/hcl2/hclwrite"

Package hclwrite deals with the problem of generating HCL configuration and of making specific surgical changes to existing HCL configurations.

It operates at a different level of abstraction than the main HCL parser and AST, since details such as the placement of comments and newlines are preserved when unchanged.

The hclwrite API follows a similar principle to XML/HTML DOM, allowing nodes to be read out, created and inserted, etc. Nodes represent syntax constructs rather than semantic concepts.

Code:

f := hclwrite.NewEmptyFile()
rootBody := f.Body()
rootBody.SetAttributeValue("string", cty.StringVal("bar")) // this is overwritten later
rootBody.AppendNewline()
rootBody.SetAttributeValue("object", cty.ObjectVal(map[string]cty.Value{
    "foo": cty.StringVal("foo"),
    "bar": cty.NumberIntVal(5),
    "baz": cty.True,
}))
rootBody.SetAttributeValue("string", cty.StringVal("foo"))
rootBody.SetAttributeValue("bool", cty.False)
rootBody.SetAttributeTraversal("path", hcl.Traversal{
    hcl.TraverseRoot{
        Name: "env",
    },
    hcl.TraverseAttr{
        Name: "PATH",
    },
})
rootBody.AppendNewline()
fooBlock := rootBody.AppendNewBlock("foo", nil)
fooBody := fooBlock.Body()
rootBody.AppendNewBlock("empty", nil)
rootBody.AppendNewline()
barBlock := rootBody.AppendNewBlock("bar", []string{"a", "b"})
barBody := barBlock.Body()

fooBody.SetAttributeValue("hello", cty.StringVal("world"))

bazBlock := barBody.AppendNewBlock("baz", nil)
bazBody := bazBlock.Body()
bazBody.SetAttributeValue("foo", cty.NumberIntVal(10))
bazBody.SetAttributeValue("beep", cty.StringVal("boop"))
bazBody.SetAttributeValue("baz", cty.ListValEmpty(cty.String))

fmt.Printf("%s", f.Bytes())

Output:

string = "foo"

object = { bar = 5, baz = true, foo = "foo" }
bool   = false
path   = env.PATH

foo {
  hello = "world"
}
empty {
}

bar "a" "b" {
  baz {
    foo  = 10
    beep = "boop"
    baz  = []
  }
}

Index

Examples

Package Files

ast.go ast_attribute.go ast_block.go ast_body.go ast_expression.go doc.go format.go generate.go native_node_sorter.go node.go parser.go public.go tokens.go

func Format Uses

func Format(src []byte) []byte

Format takes source code and performs simple whitespace changes to transform it to a canonical layout style.

Format skips constructing an AST and works directly with tokens, so it is less expensive than formatting via the AST for situations where no other changes will be made. It also ignores syntax errors and can thus be applied to partial source code, although the result in that case may not be desirable.

type Attribute Uses

type Attribute struct {
    // contains filtered or unexported fields
}

func (*Attribute) BuildTokens Uses

func (it *Attribute) BuildTokens(to Tokens) Tokens

func (*Attribute) Expr Uses

func (a *Attribute) Expr() *Expression

type Block Uses

type Block struct {
    // contains filtered or unexported fields
}

func NewBlock Uses

func NewBlock(typeName string, labels []string) *Block

NewBlock constructs a new, empty block with the given type name and labels.

func (*Block) Body Uses

func (b *Block) Body() *Body

Body returns the body that represents the content of the receiving block.

Appending to or otherwise modifying this body will make changes to the tokens that are generated between the blocks open and close braces.

func (*Block) BuildTokens Uses

func (it *Block) BuildTokens(to Tokens) Tokens

type Body Uses

type Body struct {
    // contains filtered or unexported fields
}

func (*Body) AppendBlock Uses

func (b *Body) AppendBlock(block *Block) *Block

AppendBlock appends an existing block (which must not be already attached to a body) to the end of the receiving body.

func (*Body) AppendNewBlock Uses

func (b *Body) AppendNewBlock(typeName string, labels []string) *Block

AppendNewBlock appends a new nested block to the end of the receiving body with the given type name and labels.

func (*Body) AppendNewline Uses

func (b *Body) AppendNewline()

AppendNewline appends a newline token to th end of the receiving body, which generally serves as a separator between different sets of body contents.

func (*Body) AppendUnstructuredTokens Uses

func (b *Body) AppendUnstructuredTokens(ts Tokens)

func (*Body) Attributes Uses

func (b *Body) Attributes() map[string]*Attribute

Attributes returns a new map of all of the attributes in the body, with the attribute names as the keys.

func (*Body) Blocks Uses

func (b *Body) Blocks() []*Block

Blocks returns a new slice of all the blocks in the body.

func (*Body) BuildTokens Uses

func (it *Body) BuildTokens(to Tokens) Tokens

func (*Body) Clear Uses

func (b *Body) Clear()

Clear removes all of the items from the body, making it empty.

func (*Body) GetAttribute Uses

func (b *Body) GetAttribute(name string) *Attribute

GetAttribute returns the attribute from the body that has the given name, or returns nil if there is currently no matching attribute.

func (*Body) SetAttributeTraversal Uses

func (b *Body) SetAttributeTraversal(name string, traversal hcl.Traversal) *Attribute

SetAttributeTraversal either replaces the expression of an existing attribute of the given name or adds a new attribute definition to the end of the body.

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 (*Body) SetAttributeValue Uses

func (b *Body) SetAttributeValue(name string, val cty.Value) *Attribute

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.

type Expression Uses

type Expression struct {
    // contains filtered or unexported fields
}

func NewExpressionAbsTraversal Uses

func NewExpressionAbsTraversal(traversal hcl.Traversal) *Expression

NewExpressionAbsTraversal constructs an expression that represents the given traversal, which must be absolute or this function will panic.

func NewExpressionLiteral Uses

func NewExpressionLiteral(val cty.Value) *Expression

NewExpressionLiteral constructs an an expression that represents the given literal value.

Since an unknown value cannot be represented in source code, this function will panic if the given value is unknown or contains a nested unknown value. Use val.IsWhollyKnown before calling to be sure.

HCL native syntax does not directly represent lists, maps, and sets, and instead relies on the automatic conversions to those collection types from either list or tuple constructor syntax. Therefore converting collection values to source code and re-reading them will lose type information, and the reader must provide a suitable type at decode time to recover the original value.

func (*Expression) BuildTokens Uses

func (it *Expression) BuildTokens(to Tokens) Tokens

func (*Expression) RenameVariablePrefix Uses

func (e *Expression) RenameVariablePrefix(search, replacement []string)

RenameVariablePrefix examines each of the absolute traversals in the receiving expression to see if they have the given sequence of names as a prefix prefix. If so, they are updated in place to have the given replacement names instead of that prefix.

This can be used to implement symbol renaming. The calling application can visit all relevant expressions in its input and apply the same renaming to implement a global symbol rename.

The search and replacement traversals must be the same length, or this method will panic. Only attribute access operations can be matched and replaced. Index steps never match the prefix.

Code:

src := []byte(
    "foo = a.x + a.y * b.c\n" +
        "bar = max(a.z, b.c)\n",
)
f, diags := hclwrite.ParseConfig(src, "", hcl.Pos{Line: 1, Column: 1})
if diags.HasErrors() {
    fmt.Printf("errors: %s", diags)
    return
}

// Rename references of variable "a" to "z"
for _, attr := range f.Body().Attributes() {
    attr.Expr().RenameVariablePrefix(
        []string{"a"},
        []string{"z"},
    )
}

fmt.Printf("%s", f.Bytes())

Output:

foo = z.x + z.y * b.c
bar = max(z.z, b.c)

func (*Expression) Variables Uses

func (e *Expression) Variables() []*Traversal

Variables returns the absolute traversals that exist within the receiving expression.

type File Uses

type File struct {
    // contains filtered or unexported fields
}

func NewEmptyFile Uses

func NewEmptyFile() *File

NewEmptyFile constructs a new file with no content, ready to be mutated by other calls that append to its body.

func NewFile Uses

func NewFile() *File

NewFile creates a new file object that is empty and ready to have constructs added t it.

func ParseConfig Uses

func ParseConfig(src []byte, filename string, start hcl.Pos) (*File, hcl.Diagnostics)

ParseConfig interprets the given source bytes into a *hclwrite.File. The resulting AST can be used to perform surgical edits on the source code before turning it back into bytes again.

func (*File) Body Uses

func (f *File) Body() *Body

Body returns the root body of the file, which contains the top-level attributes and blocks.

func (*File) BuildTokens Uses

func (it *File) BuildTokens(to Tokens) Tokens

func (*File) Bytes Uses

func (f *File) Bytes() []byte

Bytes returns a buffer containing the source code resulting from the tokens underlying the receiving file. If any updates have been made via the AST API, these will be reflected in the result.

func (*File) WriteTo Uses

func (f *File) WriteTo(wr io.Writer) (int64, error)

WriteTo writes the tokens underlying the receiving file to the given writer.

The tokens first have a simple formatting pass applied that adjusts only the spaces between them.

type Token Uses

type Token struct {
    Type  hclsyntax.TokenType
    Bytes []byte

    // We record the number of spaces before each token so that we can
    // reproduce the exact layout of the original file when we're making
    // surgical changes in-place. When _new_ code is created it will always
    // be in the canonical style, but we preserve layout of existing code.
    SpacesBefore int
}

Token is a single sequence of bytes annotated with a type. It is similar in purpose to hclsyntax.Token, but discards the source position information since that is not useful in code generation.

type Tokens Uses

type Tokens []*Token

Tokens is a flat list of tokens.

func TokensForTraversal Uses

func TokensForTraversal(traversal hcl.Traversal) Tokens

TokensForTraversal returns a sequence of tokens that represents the given traversal.

If the traversal is absolute then the result is a self-contained, valid reference expression. If the traversal is relative then the returned tokens could be appended to some other expression tokens to traverse into the represented expression.

func TokensForValue Uses

func TokensForValue(val cty.Value) Tokens

TokensForValue returns a sequence of tokens that represents the given constant value.

This function only supports types that are used by HCL. In particular, it does not support capsule types and will panic if given one.

It is not possible to express an unknown value in source code, so this function will panic if the given value is unknown or contains any unknown values. A caller can call the value's IsWhollyKnown method to verify that no unknown values are present before calling TokensForValue.

func (Tokens) BuildTokens Uses

func (ts Tokens) BuildTokens(to Tokens) Tokens

func (Tokens) Bytes Uses

func (ts Tokens) Bytes() []byte

func (Tokens) Columns Uses

func (ts Tokens) Columns() int

Columns returns the number of columns (grapheme clusters) the token sequence occupies. The result is not meaningful if there are newline or single-line comment tokens in the sequence.

func (Tokens) WriteTo Uses

func (ts Tokens) WriteTo(wr io.Writer) (int64, error)

WriteTo takes an io.Writer and writes the bytes for each token to it, along with the spacing that separates each token. In other words, this allows serializing the tokens to a file or other such byte stream.

type Traversal Uses

type Traversal struct {
    // contains filtered or unexported fields
}

Traversal represents a sequence of variable, attribute, and/or index operations.

func (*Traversal) BuildTokens Uses

func (it *Traversal) BuildTokens(to Tokens) Tokens

type TraverseIndex Uses

type TraverseIndex struct {
    // contains filtered or unexported fields
}

func (*TraverseIndex) BuildTokens Uses

func (it *TraverseIndex) BuildTokens(to Tokens) Tokens

type TraverseName Uses

type TraverseName struct {
    // contains filtered or unexported fields
}

func (*TraverseName) BuildTokens Uses

func (it *TraverseName) BuildTokens(to Tokens) Tokens

Package hclwrite imports 11 packages (graph) and is imported by 14 packages. Updated 2019-09-10. Refresh now. Tools for package owners.