From 4043c7d95983803217eccb53b8f7e3adedce7c18 Mon Sep 17 00:00:00 2001
From: Graham Davison <gdavison@hashicorp.com>
Date: Mon, 9 May 2022 10:24:35 -0700
Subject: [PATCH 1/5] Adds support for `count` meta-argument special case

---
 lib/fmtverbs/fmtverbs.go      |  8 ++++++++
 lib/fmtverbs/fmtverbs_test.go | 21 +++++++++++++++++++++
 2 files changed, 29 insertions(+)

diff --git a/lib/fmtverbs/fmtverbs.go b/lib/fmtverbs/fmtverbs.go
index 99ceb6dc..56447570 100644
--- a/lib/fmtverbs/fmtverbs.go
+++ b/lib/fmtverbs/fmtverbs.go
@@ -27,6 +27,10 @@ func Escape(b string) string {
 	b = regexp.MustCompile(`(provider\s+=\s+)%s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER`)
 	b = regexp.MustCompile(`(provider\s+=\s+)+%\[(\d+)\]s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER_${2}`)
 
+	// count meta-argument
+	b = regexp.MustCompile(`(count\s+=\s+)%d`).ReplaceAllString(b, `${1}var.tfmtcount`)
+	b = regexp.MustCompile(`(count\s+=\s+)+%\[(\d+)\]d`).ReplaceAllString(b, `${1}var.tfmtcount_${2}`)
+
 	// %[n]s
 	b = regexp.MustCompile(`(?m:^%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
 	b = regexp.MustCompile(`(?m:^[ \t]*%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
@@ -124,6 +128,10 @@ func Unscape(fb string) string {
 	// resource name %q
 	fb = regexp.MustCompile(`"TFMTRESNAME_q"`).ReplaceAllLiteralString(fb, `%q`)
 
+	// count meta-argument
+	fb = regexp.MustCompile(`var.tfmtcount_(\d+)`).ReplaceAllString(fb, `%[${1}]d`)
+	fb = strings.ReplaceAll(fb, "var.tfmtcount", "%d")
+
 	// provider meta-argument
 	fb = regexp.MustCompile(`tfmtprovider.PROVIDER_(\d+)`).ReplaceAllString(fb, `%[${1}]s`)
 	fb = strings.ReplaceAll(fb, "tfmtprovider.PROVIDER", "%s")
diff --git a/lib/fmtverbs/fmtverbs_test.go b/lib/fmtverbs/fmtverbs_test.go
index 0130b71c..70595bbb 100644
--- a/lib/fmtverbs/fmtverbs_test.go
+++ b/lib/fmtverbs/fmtverbs_test.go
@@ -570,6 +570,27 @@ resource "resource" "test" {
 resource "resource" "test2" {
   provider = tfmtprovider.PROVIDER_1
 }
+`,
+		},
+		{
+			name: "count meta-argument",
+			block: `
+resource "resource" "test" {
+  count = %d
+}
+
+resource "resource" "test2" {
+  count = %[2]d
+}
+`,
+			expected: `
+resource "resource" "test" {
+  count = var.tfmtcount
+}
+
+resource "resource" "test2" {
+  count = var.tfmtcount_2
+}
 `,
 		},
 	}

From abcc3d03a198ce8e7ad59fd6ec97c3b163300c61 Mon Sep 17 00:00:00 2001
From: Graham Davison <gdavison@hashicorp.com>
Date: Mon, 9 May 2022 16:08:41 -0700
Subject: [PATCH 2/5] Adds word boundary for `provider` and `count`

---
 lib/fmtverbs/fmtverbs.go      | 12 ++++++------
 lib/fmtverbs/fmtverbs_test.go | 20 ++++++++++++++++++--
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/lib/fmtverbs/fmtverbs.go b/lib/fmtverbs/fmtverbs.go
index 56447570..19a8a99a 100644
--- a/lib/fmtverbs/fmtverbs.go
+++ b/lib/fmtverbs/fmtverbs.go
@@ -24,12 +24,12 @@ func Escape(b string) string {
 
 	// provider meta-argument
 	// The provider name must be in lowercase
-	b = regexp.MustCompile(`(provider\s+=\s+)%s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER`)
-	b = regexp.MustCompile(`(provider\s+=\s+)+%\[(\d+)\]s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER_${2}`)
+	b = regexp.MustCompile(`(\bprovider\s+=\s+)%s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER`)
+	b = regexp.MustCompile(`(\bprovider\s+=\s+)+%\[(\d+)\]s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER_${2}`)
 
 	// count meta-argument
-	b = regexp.MustCompile(`(count\s+=\s+)%d`).ReplaceAllString(b, `${1}var.tfmtcount`)
-	b = regexp.MustCompile(`(count\s+=\s+)+%\[(\d+)\]d`).ReplaceAllString(b, `${1}var.tfmtcount_${2}`)
+	b = regexp.MustCompile(`(\bcount\s+=\s+)%(d)`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
+	b = regexp.MustCompile(`(\bcount\s+=\s+)+%(\[(\d+)\]d)`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
 
 	// %[n]s
 	b = regexp.MustCompile(`(?m:^%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
@@ -129,8 +129,8 @@ func Unscape(fb string) string {
 	fb = regexp.MustCompile(`"TFMTRESNAME_q"`).ReplaceAllLiteralString(fb, `%q`)
 
 	// count meta-argument
-	fb = regexp.MustCompile(`var.tfmtcount_(\d+)`).ReplaceAllString(fb, `%[${1}]d`)
-	fb = strings.ReplaceAll(fb, "var.tfmtcount", "%d")
+	fb = regexp.MustCompile(`1\s+# tfmtcount_(\[\d+\]d)`).ReplaceAllString(fb, `%${1}`)
+	fb = regexp.MustCompile(`1\s+# tfmtcount_d`).ReplaceAllString(fb, `%d`)
 
 	// provider meta-argument
 	fb = regexp.MustCompile(`tfmtprovider.PROVIDER_(\d+)`).ReplaceAllString(fb, `%[${1}]s`)
diff --git a/lib/fmtverbs/fmtverbs_test.go b/lib/fmtverbs/fmtverbs_test.go
index 70595bbb..091ede10 100644
--- a/lib/fmtverbs/fmtverbs_test.go
+++ b/lib/fmtverbs/fmtverbs_test.go
@@ -582,14 +582,30 @@ resource "resource" "test" {
 resource "resource" "test2" {
   count = %[2]d
 }
+
+resource "other_resource" "test3" {
+  replica_count = %d
+}
+
+resource "other_resource" "test4" {
+  replica_count = %[2]d
+}
 `,
 			expected: `
 resource "resource" "test" {
-  count = var.tfmtcount
+  count = 1 # tfmtcount_d
 }
 
 resource "resource" "test2" {
-  count = var.tfmtcount_2
+  count = 1 # tfmtcount_[2]d
+}
+
+resource "other_resource" "test3" {
+  replica_count = "@@_@@ TFMT:%d:TFMT @@_@@"
+}
+
+resource "other_resource" "test4" {
+  replica_count = "@@_@@ TFMT:%[2]d:TFMT @@_@@"
 }
 `,
 		},

From 25b19e04618567c262263acaac36b8b2fce5c733 Mon Sep 17 00:00:00 2001
From: Graham Davison <gdavison@hashicorp.com>
Date: Mon, 9 May 2022 17:37:32 -0700
Subject: [PATCH 3/5] Some `count` parameters take a bare `%s` string parameter
 instead of a `%d`

---
 lib/fmtverbs/fmtverbs.go      |  8 ++++----
 lib/fmtverbs/fmtverbs_test.go | 24 ++++++++++++++++++++----
 2 files changed, 24 insertions(+), 8 deletions(-)

diff --git a/lib/fmtverbs/fmtverbs.go b/lib/fmtverbs/fmtverbs.go
index 19a8a99a..ec777aa9 100644
--- a/lib/fmtverbs/fmtverbs.go
+++ b/lib/fmtverbs/fmtverbs.go
@@ -28,8 +28,8 @@ func Escape(b string) string {
 	b = regexp.MustCompile(`(\bprovider\s+=\s+)+%\[(\d+)\]s`).ReplaceAllString(b, `${1}tfmtprovider.PROVIDER_${2}`)
 
 	// count meta-argument
-	b = regexp.MustCompile(`(\bcount\s+=\s+)%(d)`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
-	b = regexp.MustCompile(`(\bcount\s+=\s+)+%(\[(\d+)\]d)`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
+	b = regexp.MustCompile(`(\bcount\s+=\s+)%([ds])`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
+	b = regexp.MustCompile(`(\bcount\s+=\s+)+%(\[(\d+)\][ds])`).ReplaceAllString(b, `${1}1 # tfmtcount_${2}`)
 
 	// %[n]s
 	b = regexp.MustCompile(`(?m:^%(\.[0-9])?\[[\d]+\][sdfgtq]$)`).ReplaceAllString(b, `#@@_@@ TFMT:$0:TMFT @@_@@#`)
@@ -129,8 +129,8 @@ func Unscape(fb string) string {
 	fb = regexp.MustCompile(`"TFMTRESNAME_q"`).ReplaceAllLiteralString(fb, `%q`)
 
 	// count meta-argument
-	fb = regexp.MustCompile(`1\s+# tfmtcount_(\[\d+\]d)`).ReplaceAllString(fb, `%${1}`)
-	fb = regexp.MustCompile(`1\s+# tfmtcount_d`).ReplaceAllString(fb, `%d`)
+	fb = regexp.MustCompile(`1\s+# tfmtcount_(\[\d+\][ds])`).ReplaceAllString(fb, `%${1}`)
+	fb = regexp.MustCompile(`1\s+# tfmtcount_([ds])`).ReplaceAllString(fb, `%${1}`)
 
 	// provider meta-argument
 	fb = regexp.MustCompile(`tfmtprovider.PROVIDER_(\d+)`).ReplaceAllString(fb, `%[${1}]s`)
diff --git a/lib/fmtverbs/fmtverbs_test.go b/lib/fmtverbs/fmtverbs_test.go
index 091ede10..e865a99e 100644
--- a/lib/fmtverbs/fmtverbs_test.go
+++ b/lib/fmtverbs/fmtverbs_test.go
@@ -583,11 +583,19 @@ resource "resource" "test2" {
   count = %[2]d
 }
 
-resource "other_resource" "test3" {
+resource "resource" "test3" {
+  count = %s
+}
+
+resource "resource" "test4" {
+  count = %[3]s
+}
+
+resource "other_resource" "test5" {
   replica_count = %d
 }
 
-resource "other_resource" "test4" {
+resource "other_resource" "test6" {
   replica_count = %[2]d
 }
 `,
@@ -600,11 +608,19 @@ resource "resource" "test2" {
   count = 1 # tfmtcount_[2]d
 }
 
-resource "other_resource" "test3" {
+resource "resource" "test3" {
+  count = 1 # tfmtcount_s
+}
+
+resource "resource" "test4" {
+  count = 1 # tfmtcount_[3]s
+}
+
+resource "other_resource" "test5" {
   replica_count = "@@_@@ TFMT:%d:TFMT @@_@@"
 }
 
-resource "other_resource" "test4" {
+resource "other_resource" "test6" {
   replica_count = "@@_@@ TFMT:%[2]d:TFMT @@_@@"
 }
 `,

From b8ea302b4da96bb303334d3384a890b78d089d34 Mon Sep 17 00:00:00 2001
From: Graham Davison <gdavison@hashicorp.com>
Date: Tue, 9 Aug 2022 13:45:14 -0700
Subject: [PATCH 4/5] Removes `io/ioutil`

---
 lib/blocks/blockreader.go | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/lib/blocks/blockreader.go b/lib/blocks/blockreader.go
index 0fa651e9..13d42f9c 100644
--- a/lib/blocks/blockreader.go
+++ b/lib/blocks/blockreader.go
@@ -9,7 +9,6 @@ import (
 	"go/parser"
 	"go/token"
 	"io"
-	"io/ioutil"
 	"path/filepath"
 	"regexp"
 	"strconv"
@@ -157,7 +156,7 @@ func (br *Reader) DoTheThing(fs afero.Fs, filename string, stdin io.Reader, stdo
 		if !br.ReadOnly {
 			br.Writer = buf
 		} else {
-			br.Writer = ioutil.Discard
+			br.Writer = io.Discard
 		}
 	} else {
 		br.FileName = "stdin"
@@ -165,7 +164,7 @@ func (br *Reader) DoTheThing(fs afero.Fs, filename string, stdin io.Reader, stdo
 		br.Writer = stdout
 
 		if br.ReadOnly {
-			br.Writer = ioutil.Discard
+			br.Writer = io.Discard
 		}
 	}
 
@@ -230,7 +229,7 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
 			buf = bytes.NewBuffer([]byte{})
 			br.Writer = buf
 		} else {
-			br.Writer = ioutil.Discard
+			br.Writer = io.Discard
 		}
 	} else {
 		br.FileName = "stdin"
@@ -238,7 +237,7 @@ func (br *Reader) doTheThingPatternMatch(fs afero.Fs, filename string, stdin io.
 		br.Writer = stdout
 
 		if br.ReadOnly {
-			br.Writer = ioutil.Discard
+			br.Writer = io.Discard
 		}
 	}
 

From 722a692e3348f7773d23f5e80d2d75b719828499 Mon Sep 17 00:00:00 2001
From: Graham Davison <gdavison@hashicorp.com>
Date: Tue, 9 Aug 2022 14:19:00 -0700
Subject: [PATCH 5/5] Removes more `io/ioutil`

---
 lib/upgrade012/upgrade.go | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/lib/upgrade012/upgrade.go b/lib/upgrade012/upgrade.go
index 762827bd..5546ff1e 100644
--- a/lib/upgrade012/upgrade.go
+++ b/lib/upgrade012/upgrade.go
@@ -4,7 +4,6 @@ import (
 	"bytes"
 	"context"
 	"fmt"
-	"io/ioutil"
 	"os"
 	"strings"
 
@@ -14,13 +13,13 @@ import (
 
 func Block(ctx context.Context, tfPath string, log *logrus.Logger, b string) (string, error) {
 	// Make temp directory
-	tempDir, err := ioutil.TempDir(".", "tmp-module")
+	tempDir, err := os.MkdirTemp(".", "tmp-module")
 	if err != nil {
 		log.Fatal(err)
 	}
 
 	// Create temp file
-	tmpFile, err := ioutil.TempFile(tempDir, "*.tf")
+	tmpFile, err := os.CreateTemp(tempDir, "*.tf")
 	if err != nil {
 		return "", err
 	}
@@ -55,7 +54,7 @@ func Block(ctx context.Context, tfPath string, log *logrus.Logger, b string) (st
 	}
 
 	// Read from temp file
-	raw, err := ioutil.ReadFile(tmpFile.Name())
+	raw, err := os.ReadFile(tmpFile.Name())
 	if err != nil {
 		return "", fmt.Errorf("failed to read %s: %w", tmpFile.Name(), err)
 	}