@@ -200,6 +200,55 @@ func convertDynamicRepSpecs(resourceb *hclwrite.Body, dSpec dynamicBlock, diskSi
200
200
return nil
201
201
}
202
202
203
+ // Helper function to add attributes in order
204
+ func addAttributesInOrder (targetBody * hclwrite.Body , sourceAttrs map [string ]* hclwrite.Attribute ,
205
+ orderedNames []string ) {
206
+ // Add ordered attributes first
207
+ for _ , name := range orderedNames {
208
+ if attr , exists := sourceAttrs [name ]; exists {
209
+ targetBody .SetAttributeRaw (name , hcl .TokensFromExpr (hcl .GetAttrExpr (attr )))
210
+ }
211
+ }
212
+
213
+ // Add any remaining attributes alphabetically
214
+ var remainingAttrs []string
215
+ for name := range sourceAttrs {
216
+ found := false
217
+ for _ , orderedName := range orderedNames {
218
+ if name == orderedName {
219
+ found = true
220
+ break
221
+ }
222
+ }
223
+ if ! found {
224
+ remainingAttrs = append (remainingAttrs , name )
225
+ }
226
+ }
227
+ slices .Sort (remainingAttrs )
228
+ for _ , name := range remainingAttrs {
229
+ attr := sourceAttrs [name ]
230
+ targetBody .SetAttributeRaw (name , hcl .TokensFromExpr (hcl .GetAttrExpr (attr )))
231
+ }
232
+ }
233
+
234
+ // Helper function to process blocks for region configs
235
+ func processRegionConfigBlocks (targetBody * hclwrite.Body , blocks []* hclwrite.Block ) {
236
+ for _ , block := range blocks {
237
+ blockType := block .Type ()
238
+ blockFile := hclwrite .NewEmptyFile ()
239
+ blockBody := blockFile .Body ()
240
+
241
+ // For electable_specs, use specific order: instance_size, node_count
242
+ var attrOrder []string
243
+ if blockType == "electable_specs" {
244
+ attrOrder = []string {"instance_size" , "node_count" }
245
+ }
246
+
247
+ addAttributesInOrder (blockBody , block .Body ().Attributes (), attrOrder )
248
+ targetBody .SetAttributeRaw (blockType , hcl .TokensObject (blockBody ))
249
+ }
250
+ }
251
+
203
252
func convertDynamicRepSpecsWithDynamicConfig (resourceb * hclwrite.Body , dSpec , dConfig dynamicBlock ,
204
253
diskSizeGB hclwrite.Tokens ) error {
205
254
// Get the block name from the dynamic block
@@ -226,51 +275,20 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
226
275
}
227
276
}
228
277
229
- // Don't convert specs blocks to attributes - we'll handle them manually in the string building
230
-
231
278
// Build the expression using HCL functions
232
- configForEach := replaceDynamicBlockReferences (hcl .GetAttrExpr (dConfig .forEach ), nRepSpecs , nSpec )
279
+ // Use standardized property name (region_configs) instead of the actual for_each collection
280
+ configForEach := fmt .Sprintf ("%s.%s" , nSpec , nConfig )
233
281
234
282
// Create the inner region_configs body
235
283
regionConfigFile := hclwrite .NewEmptyFile ()
236
284
regionConfigBody := regionConfigFile .Body ()
237
285
238
- // Add all attributes generically in alphabetical order
239
- attrs := dConfig .content .Body ().Attributes ()
240
- attrNames := make ([]string , 0 , len (attrs ))
241
- for name := range attrs {
242
- attrNames = append (attrNames , name )
243
- }
244
- slices .Sort (attrNames )
245
-
246
- for _ , name := range attrNames {
247
- attr := attrs [name ]
248
- regionConfigBody .SetAttributeRaw (name , hcl .TokensFromExpr (hcl .GetAttrExpr (attr )))
249
- }
286
+ // Add attributes in a specific order for consistency
287
+ orderedAttrs := []string {"priority" , "provider_name" , "region_name" }
288
+ addAttributesInOrder (regionConfigBody , dConfig .content .Body ().Attributes (), orderedAttrs )
250
289
251
290
// Add all blocks generically as objects
252
- for _ , block := range dConfig .content .Body ().Blocks () {
253
- blockType := block .Type ()
254
-
255
- // Create a new body for the block
256
- blockFile := hclwrite .NewEmptyFile ()
257
- blockBody := blockFile .Body ()
258
-
259
- // Add block attributes in alphabetical order
260
- blockAttrs := block .Body ().Attributes ()
261
- blockAttrNames := make ([]string , 0 , len (blockAttrs ))
262
- for name := range blockAttrs {
263
- blockAttrNames = append (blockAttrNames , name )
264
- }
265
- slices .Sort (blockAttrNames )
266
-
267
- for _ , attrName := range blockAttrNames {
268
- attr := blockAttrs [attrName ]
269
- blockBody .SetAttributeRaw (attrName , hcl .TokensFromExpr (hcl .GetAttrExpr (attr )))
270
- }
271
-
272
- regionConfigBody .SetAttributeRaw (blockType , hcl .TokensObject (blockBody ))
273
- }
291
+ processRegionConfigBlocks (regionConfigBody , dConfig .content .Body ().Blocks ())
274
292
275
293
// Build the region_configs for expression
276
294
regionForExpr := fmt .Sprintf ("for %s in %s :" , nRegion , configForEach )
@@ -306,8 +324,46 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
306
324
return nil
307
325
}
308
326
// No num_shards, handle like without nested shards
309
- // Reuse the block name from the dynamic block that was already obtained
327
+ return convertDynamicRepSpecsWithoutNumShards (resourceb , dSpec , dConfig , diskSizeGB , configBlockName )
328
+ }
310
329
330
+ // Helper function to add attributes with transformation
331
+ func addAttributesWithTransform (targetBody * hclwrite.Body , sourceAttrs map [string ]* hclwrite.Attribute ,
332
+ orderedNames []string , configBlockName string , transformFunc func (string ) string ) {
333
+ // Add ordered attributes first
334
+ for _ , name := range orderedNames {
335
+ if attr , exists := sourceAttrs [name ]; exists {
336
+ expr := hcl .GetAttrExpr (attr )
337
+ // First replace nested dynamic block references
338
+ expr = replaceDynamicBlockReferences (expr , configBlockName , nRegion )
339
+ // Then replace outer dynamic block references
340
+ expr = replaceDynamicBlockReferences (expr , nRepSpecs , nSpec )
341
+ targetBody .SetAttributeRaw (name , hcl .TokensFromExpr (expr ))
342
+ }
343
+ }
344
+
345
+ // Add any remaining attributes
346
+ for name , attr := range sourceAttrs {
347
+ found := false
348
+ for _ , orderedName := range orderedNames {
349
+ if name == orderedName {
350
+ found = true
351
+ break
352
+ }
353
+ }
354
+ if ! found {
355
+ expr := hcl .GetAttrExpr (attr )
356
+ // First replace nested dynamic block references
357
+ expr = replaceDynamicBlockReferences (expr , configBlockName , nRegion )
358
+ // Then replace outer dynamic block references
359
+ expr = replaceDynamicBlockReferences (expr , nRepSpecs , nSpec )
360
+ targetBody .SetAttributeRaw (name , hcl .TokensFromExpr (expr ))
361
+ }
362
+ }
363
+ }
364
+
365
+ func convertDynamicRepSpecsWithoutNumShards (resourceb * hclwrite.Body , dSpec , dConfig dynamicBlock ,
366
+ diskSizeGB hclwrite.Tokens , configBlockName string ) error {
311
367
// Get zone_name if present
312
368
repSpecFile := hclwrite .NewEmptyFile ()
313
369
repSpecb := repSpecFile .Body ()
@@ -321,28 +377,22 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
321
377
configFile := hclwrite .NewEmptyFile ()
322
378
configb := configFile .Body ()
323
379
324
- // Copy and transform attributes
325
- for name , attr := range dConfig .content .Body ().Attributes () {
326
- expr := hcl .GetAttrExpr (attr )
327
- // First replace nested dynamic block references
328
- expr = replaceDynamicBlockReferences (expr , configBlockName , nRegion )
329
- // Then replace outer dynamic block references
330
- expr = replaceDynamicBlockReferences (expr , nRepSpecs , nSpec )
331
- configb .SetAttributeRaw (name , hcl .TokensFromExpr (expr ))
332
- }
380
+ // Copy and transform attributes in a specific order for consistency
381
+ orderedAttrs := []string {"priority" , "provider_name" , "region_name" }
382
+ addAttributesWithTransform (configb , dConfig .content .Body ().Attributes (), orderedAttrs , configBlockName , nil )
333
383
334
384
// Process blocks and transform their references
335
385
for _ , block := range dConfig .content .Body ().Blocks () {
336
386
newBlock := configb .AppendNewBlock (block .Type (), block .Labels ())
337
387
newBlockb := newBlock .Body ()
338
- for name , attr := range block .Body ().Attributes () {
339
- expr := hcl .GetAttrExpr (attr )
340
- // First replace nested dynamic block references
341
- expr = replaceDynamicBlockReferences (expr , configBlockName , nRegion )
342
- // Then replace outer dynamic block references
343
- expr = replaceDynamicBlockReferences (expr , nRepSpecs , nSpec )
344
- newBlockb .SetAttributeRaw (name , hcl .TokensFromExpr (expr ))
388
+
389
+ // Order attributes for consistency
390
+ var attrOrder []string
391
+ if block .Type () == "electable_specs" {
392
+ attrOrder = []string {"instance_size" , "node_count" }
345
393
}
394
+
395
+ addAttributesWithTransform (newBlockb , block .Body ().Attributes (), attrOrder , configBlockName , nil )
346
396
}
347
397
348
398
// Process specs
@@ -353,22 +403,25 @@ func convertDynamicRepSpecsWithDynamicConfig(resourceb *hclwrite.Body, dSpec, dC
353
403
fillSpecOpt (configb , nAnalyticsAutoScaling , nil )
354
404
355
405
// Build the nested for expression for region_configs
356
- configForEach := replaceDynamicBlockReferences (hcl .GetAttrExpr (dConfig .forEach ), nRepSpecs , nSpec )
357
- var regionTokens2 hclwrite.Tokens
358
- regionTokens2 = append (regionTokens2 , hcl .TokensFromExpr ("[\n " )... )
359
- forExpr := fmt .Sprintf (" for %s in %s : " , nRegion , configForEach )
360
- regionTokens2 = append (regionTokens2 , hcl .TokensFromExpr (forExpr )... )
361
- regionTokens2 = append (regionTokens2 , hcl .TokensObject (configb )... )
362
- regionTokens2 = append (regionTokens2 , hcl .TokensFromExpr ("\n ]" )... )
363
- repSpecb .SetAttributeRaw (nConfig , regionTokens2 )
364
-
365
- // Build the for expression without range
366
- var tokens hclwrite.Tokens
367
- tokens = append (tokens , hcl .TokensFromExpr ("[\n " )... )
368
- specForExpr := fmt .Sprintf (" for %s in %s : " , nSpec , hcl .GetAttrExpr (dSpec .forEach ))
369
- tokens = append (tokens , hcl .TokensFromExpr (specForExpr )... )
370
- tokens = append (tokens , hcl .TokensObject (repSpecb )... )
371
- tokens = append (tokens , hcl .TokensFromExpr ("\n ]" )... )
406
+ // Use standardized property name (region_configs) instead of the actual for_each collection
407
+ configForEach := fmt .Sprintf ("%s.%s" , nSpec , nConfig )
408
+
409
+ // Build the region_configs for expression
410
+ regionForExpr := fmt .Sprintf ("for %s in %s :" , nRegion , configForEach )
411
+ regionTokens := hcl .TokensFromExpr (regionForExpr )
412
+ regionTokens = append (regionTokens , hcl .TokensObject (configb )... )
413
+
414
+ repSpecb .SetAttributeRaw (nConfig , hcl .EncloseBracketsNewLines (regionTokens ))
415
+
416
+ // Build the for expression as an array wrapped in flatten
417
+ // Format: flatten([for spec in ... : [ { ... } ] ])
418
+ forExpr := fmt .Sprintf ("for %s in %s : [\n " , nSpec , hcl .GetAttrExpr (dSpec .forEach ))
419
+ innerTokens := hcl .TokensFromExpr (forExpr )
420
+ innerTokens = append (innerTokens , hcl .TokensObject (repSpecb )... )
421
+ innerTokens = append (innerTokens , hcl .TokensFromExpr ("\n ]" )... )
422
+
423
+ // Apply flatten to the entire expression
424
+ tokens := hcl .TokensFuncFlatten (innerTokens )
372
425
373
426
resourceb .RemoveBlock (dSpec .block )
374
427
resourceb .SetAttributeRaw (nRepSpecs , tokens )
0 commit comments