6c4344623b
The main HCL package is more visible this way, and so it's easier than having to pick it out from dozens of other package directories.
84 lines
2.8 KiB
Go
84 lines
2.8 KiB
Go
package transform
|
|
|
|
import (
|
|
"github.com/hashicorp/hcl/v2"
|
|
)
|
|
|
|
// Shallow is equivalent to calling transformer.TransformBody(body), and
|
|
// is provided only for completeness of the top-level API.
|
|
func Shallow(body hcl.Body, transformer Transformer) hcl.Body {
|
|
return transformer.TransformBody(body)
|
|
}
|
|
|
|
// Deep applies the given transform to the given body and then
|
|
// wraps the result such that any descendent blocks that are decoded will
|
|
// also have the transform applied to their bodies.
|
|
//
|
|
// This allows for language extensions that define a particular block type
|
|
// for a particular body and all nested blocks within it.
|
|
//
|
|
// Due to the wrapping behavior, the body resulting from this function
|
|
// will not be of the type returned by the transformer. Callers may call
|
|
// only the methods defined for interface hcl.Body, and may not type-assert
|
|
// to access other methods.
|
|
func Deep(body hcl.Body, transformer Transformer) hcl.Body {
|
|
return deepWrapper{
|
|
Transformed: transformer.TransformBody(body),
|
|
Transformer: transformer,
|
|
}
|
|
}
|
|
|
|
// deepWrapper is a hcl.Body implementation that ensures that a given
|
|
// transformer is applied to another given body when content is extracted,
|
|
// and that it recursively applies to any child blocks that are extracted.
|
|
type deepWrapper struct {
|
|
Transformed hcl.Body
|
|
Transformer Transformer
|
|
}
|
|
|
|
func (w deepWrapper) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostics) {
|
|
content, diags := w.Transformed.Content(schema)
|
|
content = w.transformContent(content)
|
|
return content, diags
|
|
}
|
|
|
|
func (w deepWrapper) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Body, hcl.Diagnostics) {
|
|
content, remain, diags := w.Transformed.PartialContent(schema)
|
|
content = w.transformContent(content)
|
|
return content, remain, diags
|
|
}
|
|
|
|
func (w deepWrapper) transformContent(content *hcl.BodyContent) *hcl.BodyContent {
|
|
if len(content.Blocks) == 0 {
|
|
// Easy path: if there are no blocks then there are no child bodies to wrap
|
|
return content
|
|
}
|
|
|
|
// Since we're going to change things here, we'll be polite and clone the
|
|
// structure so that we don't risk impacting any internal state of the
|
|
// original body.
|
|
ret := &hcl.BodyContent{
|
|
Attributes: content.Attributes,
|
|
MissingItemRange: content.MissingItemRange,
|
|
Blocks: make(hcl.Blocks, len(content.Blocks)),
|
|
}
|
|
|
|
for i, givenBlock := range content.Blocks {
|
|
// Shallow-copy the block so we can mutate it
|
|
newBlock := *givenBlock
|
|
newBlock.Body = Deep(newBlock.Body, w.Transformer)
|
|
ret.Blocks[i] = &newBlock
|
|
}
|
|
|
|
return ret
|
|
}
|
|
|
|
func (w deepWrapper) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
|
|
// Attributes can't have bodies or nested blocks, so this is just a thin wrapper.
|
|
return w.Transformed.JustAttributes()
|
|
}
|
|
|
|
func (w deepWrapper) MissingItemRange() hcl.Range {
|
|
return w.Transformed.MissingItemRange()
|
|
}
|