pkg/transform_rename_block_element.go (106 lines of code) (raw):

package pkg import ( "strings" "github.com/Azure/golden" "github.com/Azure/mapotf/pkg/terraform" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/hashicorp/hcl/v2/hclwrite" ) var _ Transform = &RenameAttributeOrNestedBlockTransform{} type Rename struct { ResourceType string `hcl:"resource_type"` // We'll deprecate `attribute_path` in favor of `element_path`. AttributePath []string `hcl:"attribute_path,optional" validate:"excluded_with=element_path"` ElementPath []string `hcl:"element_path,optional" validate:"excluded_with=attribute_path,required_without=attribute_path"` NewName string `hcl:"new_name" validate:"required"` RenameOnlyNewNameAbsent bool `hcl:"rename_only_new_name_absent,optional" default:"false"` } type RenameAttributeOrNestedBlockTransform struct { *golden.BaseBlock *BaseTransform Renames []Rename `hcl:"rename,block"` } func (r *RenameAttributeOrNestedBlockTransform) Type() string { return "rename_block_element" } func (r *RenameAttributeOrNestedBlockTransform) Apply() error { cfg := r.Config().(*MetaProgrammingTFConfig) for _, rename := range r.Renames { r.applyRename(rename, cfg) } return nil } func (r *RenameAttributeOrNestedBlockTransform) applyRename(rename Rename, cfg *MetaProgrammingTFConfig) { resourceType := rename.ResourceType blocks := cfg.resourceBlocks if strings.HasPrefix(resourceType, "data.") { resourceType = strings.TrimPrefix(resourceType, "data.") blocks = cfg.dataBlocks } var matchedBlocks []*terraform.RootBlock for _, b := range blocks { if b.Labels[0] == resourceType { matchedBlocks = append(matchedBlocks, b) } } path := rename.AttributePath if len(path) == 0 { path = rename.ElementPath } r.rename(castBlockSlice(matchedBlocks), path, rename.NewName, rename.RenameOnlyNewNameAbsent) } func (r *RenameAttributeOrNestedBlockTransform) rename(blocks []terraform.Block, attributePath []string, newName string, renameOnlyNewNameAbsent bool) { if len(attributePath) == 1 { old := attributePath[0] for _, b := range blocks { body := b.WriteBody() attributes := body.Attributes() attr, ok := attributes[old] if ok { if _, newNameExist := attributes[newName]; !newNameExist || !renameOnlyNewNameAbsent { body.SetAttributeRaw(newName, attr.Expr().BuildTokens(nil)) } body.RemoveAttribute(old) continue } for _, nb := range body.Blocks() { if r.nestedBlockType(nb) != old { continue } r.setNestedBlockType(nb, old, newName) } } return } nbName := attributePath[0] for _, b := range blocks { nestedBlocks, ok := b.GetNestedBlocks()[nbName] if !ok { continue } r.rename(castBlockSlice(nestedBlocks), attributePath[1:], newName, false) } } func (r *RenameAttributeOrNestedBlockTransform) nestedBlockType(nb *hclwrite.Block) string { if nb.Type() == "dynamic" { return nb.Labels()[0] } return nb.Type() } func (r *RenameAttributeOrNestedBlockTransform) setNestedBlockType(nb *hclwrite.Block, oldName, newName string) { if nb.Type() == "dynamic" { nb.SetLabels([]string{newName}) nb.Body().SetAttributeRaw("iterator", hclwrite.Tokens{&hclwrite.Token{ Type: hclsyntax.TokenIdent, Bytes: []byte(oldName), }}) } else { nb.SetType(newName) } } func castBlockSlice[T terraform.Block](s []T) []terraform.Block { ret := make([]terraform.Block, len(s)) for i, v := range s { ret[i] = v } return ret }