Skip to content

Commit 5c140ce

Browse files
authored
Merge pull request #506 from raymyers/set-attr-name
hclwrite: Add RenameAttribute on Body
2 parents ba07594 + 1ad7abd commit 5c140ce

File tree

3 files changed

+185
-0
lines changed

3 files changed

+185
-0
lines changed

hclwrite/ast_attribute.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,9 @@ func (a *Attribute) init(name string, expr *Expression) {
4949
func (a *Attribute) Expr() *Expression {
5050
return a.expr.content.(*Expression)
5151
}
52+
53+
// setName updates the name of the attribute.
54+
func (a *Attribute) setName(name string) {
55+
nameObj := newIdentifier(newIdentToken(name))
56+
a.name = a.name.ReplaceWith(nameObj)
57+
}

hclwrite/ast_body.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ func (b *Body) getAttributeNode(name string) *node {
103103
return nil
104104
}
105105

106+
// RenameAttribute changes the attribute named fromName to toName.
107+
// Takes no action if fromName is missing or there is already a
108+
// conflicting attribute called toName.
109+
//
110+
// Returns true if the rename succeeded.
111+
func (b *Body) RenameAttribute(fromName, toName string) bool {
112+
attr := b.GetAttribute(fromName)
113+
conflictingAttr := b.GetAttribute(toName)
114+
if attr == nil || conflictingAttr != nil {
115+
return false
116+
}
117+
attr.setName(toName)
118+
return true
119+
}
120+
106121
// FirstMatchingBlock returns a first matching block from the body that has the
107122
// given name and labels or returns nil if there is currently no matching
108123
// block.

hclwrite/ast_body_test.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,6 +1149,170 @@ func TestBodyRemoveAttribute(t *testing.T) {
11491149
}
11501150
}
11511151

1152+
func TestBodyRenameAttribute(t *testing.T) {
1153+
tests := []struct {
1154+
src string
1155+
oldName string
1156+
newName string
1157+
want Tokens
1158+
}{
1159+
{
1160+
"",
1161+
"a",
1162+
"b",
1163+
Tokens{
1164+
{
1165+
Type: hclsyntax.TokenEOF,
1166+
Bytes: []byte{},
1167+
SpacesBefore: 0,
1168+
},
1169+
},
1170+
},
1171+
{
1172+
"a = false\n",
1173+
"a",
1174+
"b",
1175+
Tokens{
1176+
{
1177+
Type: hclsyntax.TokenIdent,
1178+
Bytes: []byte{'b'},
1179+
SpacesBefore: 0,
1180+
},
1181+
{
1182+
Type: hclsyntax.TokenEqual,
1183+
Bytes: []byte{'='},
1184+
SpacesBefore: 1,
1185+
},
1186+
{
1187+
Type: hclsyntax.TokenIdent,
1188+
Bytes: []byte("false"),
1189+
SpacesBefore: 1,
1190+
},
1191+
{
1192+
Type: hclsyntax.TokenNewline,
1193+
Bytes: []byte{'\n'},
1194+
SpacesBefore: 0,
1195+
},
1196+
{
1197+
Type: hclsyntax.TokenEOF,
1198+
Bytes: []byte{},
1199+
SpacesBefore: 0,
1200+
},
1201+
},
1202+
},
1203+
{
1204+
"a = false\n",
1205+
"b",
1206+
"c",
1207+
Tokens{
1208+
{
1209+
Type: hclsyntax.TokenIdent,
1210+
Bytes: []byte{'a'},
1211+
SpacesBefore: 0,
1212+
},
1213+
{
1214+
Type: hclsyntax.TokenEqual,
1215+
Bytes: []byte{'='},
1216+
SpacesBefore: 1,
1217+
},
1218+
{
1219+
Type: hclsyntax.TokenIdent,
1220+
Bytes: []byte("false"),
1221+
SpacesBefore: 1,
1222+
},
1223+
{
1224+
Type: hclsyntax.TokenNewline,
1225+
Bytes: []byte{'\n'},
1226+
SpacesBefore: 0,
1227+
},
1228+
{
1229+
Type: hclsyntax.TokenEOF,
1230+
Bytes: []byte{},
1231+
SpacesBefore: 0,
1232+
},
1233+
},
1234+
},
1235+
{
1236+
"a = false\nb = false\n",
1237+
"a",
1238+
"b",
1239+
Tokens{
1240+
{
1241+
Type: hclsyntax.TokenIdent,
1242+
Bytes: []byte{'a'},
1243+
SpacesBefore: 0,
1244+
},
1245+
{
1246+
Type: hclsyntax.TokenEqual,
1247+
Bytes: []byte{'='},
1248+
SpacesBefore: 1,
1249+
},
1250+
{
1251+
Type: hclsyntax.TokenIdent,
1252+
Bytes: []byte("false"),
1253+
SpacesBefore: 1,
1254+
},
1255+
{
1256+
Type: hclsyntax.TokenNewline,
1257+
Bytes: []byte{'\n'},
1258+
SpacesBefore: 0,
1259+
},
1260+
{
1261+
Type: hclsyntax.TokenIdent,
1262+
Bytes: []byte{'b'},
1263+
SpacesBefore: 0,
1264+
},
1265+
{
1266+
Type: hclsyntax.TokenEqual,
1267+
Bytes: []byte{'='},
1268+
SpacesBefore: 1,
1269+
},
1270+
{
1271+
Type: hclsyntax.TokenIdent,
1272+
Bytes: []byte("false"),
1273+
SpacesBefore: 1,
1274+
},
1275+
{
1276+
Type: hclsyntax.TokenNewline,
1277+
Bytes: []byte{'\n'},
1278+
SpacesBefore: 0,
1279+
},
1280+
{
1281+
Type: hclsyntax.TokenEOF,
1282+
Bytes: []byte{},
1283+
SpacesBefore: 0,
1284+
},
1285+
},
1286+
},
1287+
}
1288+
1289+
for _, test := range tests {
1290+
t.Run(fmt.Sprintf("%s->%s in %s", test.oldName, test.newName, test.src), func(t *testing.T) {
1291+
f, diags := ParseConfig([]byte(test.src), "", hcl.Pos{Line: 1, Column: 1})
1292+
if len(diags) != 0 {
1293+
for _, diag := range diags {
1294+
t.Logf("- %s", diag.Error())
1295+
}
1296+
t.Fatalf("unexpected diagnostics")
1297+
}
1298+
oldExists := nil != f.Body().GetAttribute(test.oldName)
1299+
newExists := nil != f.Body().GetAttribute(test.newName)
1300+
shouldSucceed := (oldExists && !newExists)
1301+
success := f.Body().RenameAttribute(test.oldName, test.newName)
1302+
1303+
got := f.BuildTokens(nil)
1304+
format(got)
1305+
if !reflect.DeepEqual(got, test.want) {
1306+
diff := cmp.Diff(test.want, got)
1307+
t.Errorf("wrong result\ngot: %s\nwant: %s\ndiff:\n%s", spew.Sdump(got), spew.Sdump(test.want), diff)
1308+
}
1309+
if success != shouldSucceed {
1310+
t.Errorf("RenameAttribute returned %v when it should have returned %v ", success, shouldSucceed)
1311+
}
1312+
})
1313+
}
1314+
}
1315+
11521316
func TestBodyAppendBlock(t *testing.T) {
11531317
tests := []struct {
11541318
src string

0 commit comments

Comments
 (0)