Repository: daixiang0/gci (go)

Issue:
0.6.0 has extra newline bug with multi custom prefix
test 0.4.3 and 0.5.0 is OK.

with 0.6.0, when we have both org level Prefix and project level Prefix, but the imports does not contians any org level Prefix things, it will put extra newline before project level Preifx

with command:

```
gci diff  -s standard -s default -s 'Prefix(code.example.com)' -s 'Prefix(code.example.com/foo/bar/project)' --skip-generated .
```

so I have org level Prefix `code.example.com` 

and 

 project level Prefix `code.example.com/foo/bar/project`


`a.go` for re-produce:

```
package demo

import (
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo/options"

	"code.example.com/foo/bar/project/constant"
 )
```

test 0.4.3 and 0.5.0 will not change this.

```
go install github.com/daixiang0/gci@v0.5.0

# or

go install github.com/daixiang0/gci@v0.4.3
```


but 0.6.0 will:

```
go install github.com/daixiang0/gci@v0.6.0
```

```diff
--- a.go
+++ a.go
@@ -4,5 +4,6 @@
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/mongo/options"
 
+
 	"code.example.com/foo/bar/project/constant"
  )
```



Pull request:
fix bugs when sections mismatch
Fix #93 

Signed-off-by: Loong <loong.dai@intel.com>

Patch:
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 8ac0ea2..b32148b 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -11,11 +11,11 @@ import (
 )
 
 var defaultOrder = map[string]int{
-	"standard": 0,
-	"default":  1,
-	"custom":   2,
-	"blank":    3,
-	"dot":      4,
+	section.StandardType: 0,
+	section.DefaultType:  1,
+	section.CustomType:   2,
+	section.BlankType:    3,
+	section.DotType:      4,
 }
 
 type BoolConfig struct {
@@ -52,16 +52,11 @@ func (g YamlConfig) Parse() (*Config, error) {
 	// if default order sorted sections
 	if !g.Cfg.CustomOrder {
 		sort.Slice(sections, func(i, j int) bool {
-			sectionI, sectionJ := sections[i].String(), sections[j].String()
+			sectionI, sectionJ := sections[i].Type(), sections[j].Type()
 
-			if strings.HasPrefix(sectionI, "prefix(") {
-				sectionI = "custom"
+			if strings.Compare(sectionI, sectionJ) == 0 {
+				return strings.Compare(sections[i].String(), sections[j].String()) < 0
 			}
-
-			if strings.HasPrefix(sectionJ, "prefix(") {
-				sectionJ = "custom"
-			}
-
 			return defaultOrder[sectionI] < defaultOrder[sectionJ]
 		})
 	}
diff --git a/pkg/gci/gci.go b/pkg/gci/gci.go
index 23cc646..a8a64a2 100644
--- a/pkg/gci/gci.go
+++ b/pkg/gci/gci.go
@@ -5,8 +5,6 @@ import (
 	"errors"
 	"fmt"
 	"os"
-	"sort"
-	"strings"
 	"sync"
 
 	"github.com/hexops/gotextdiff"
@@ -143,39 +141,12 @@ func LoadFormatGoFile(file io.FileObj, cfg config.Config) (src, dist []byte, err
 	head := src[:headEnd]
 	tail := src[tailStart:]
 
-	// sort for custom sections
-	customKeys := make([]string, 0, len(result))
-	for k := range result {
-		if strings.HasPrefix(k, "prefix(") {
-			customKeys = append(customKeys, k)
-		}
-	}
-
 	firstWithIndex := true
 
 	var body []byte
 
 	// order by section list
 	for _, s := range cfg.Sections {
-		if strings.HasPrefix(s.String(), "prefix(") {
-			if len(customKeys) > 0 {
-				if body != nil && len(body) > 0 {
-					body = append(body, utils.Linebreak)
-				}
-				sort.Sort(sort.StringSlice(customKeys))
-				for _, k := range customKeys {
-					if !strings.Contains(s.String(), k) {
-						continue
-					}
-					for _, d := range result[k] {
-						AddIndent(&body, &firstWithIndex)
-						body = append(body, src[d.Start:d.End]...)
-					}
-				}
-			}
-
-			continue
-		}
 		if len(result[s.String()]) > 0 {
 			if body != nil && len(body) > 0 {
 				body = append(body, utils.Linebreak)
diff --git a/pkg/section/blank.go b/pkg/section/blank.go
index d5fddc4..4a27417 100644
--- a/pkg/section/blank.go
+++ b/pkg/section/blank.go
@@ -7,6 +7,8 @@ import (
 
 type Blank struct{}
 
+const BlankType = "blank"
+
 func (b Blank) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
 	if spec.Name == "_" {
 		return specificity.NameMatch{}
@@ -15,5 +17,9 @@ func (b Blank) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecifi
 }
 
 func (b Blank) String() string {
-	return "blank"
+	return BlankType
+}
+
+func (b Blank) Type() string {
+	return BlankType
 }
diff --git a/pkg/section/commentline.go b/pkg/section/commentline.go
index 94bf0d8..c3ddd08 100644
--- a/pkg/section/commentline.go
+++ b/pkg/section/commentline.go
@@ -18,3 +18,7 @@ func (c CommentLine) MatchSpecificity(spec *parse.GciImports) specificity.MatchS
 func (c CommentLine) String() string {
 	return fmt.Sprintf("commentline(%s)", c.Comment)
 }
+
+func (c CommentLine) Type() string {
+	return "commentline"
+}
diff --git a/pkg/section/default.go b/pkg/section/default.go
index f0a8db7..3af07a0 100644
--- a/pkg/section/default.go
+++ b/pkg/section/default.go
@@ -5,7 +5,7 @@ import (
 	"github.com/daixiang0/gci/pkg/specificity"
 )
 
-const defaultName = "default"
+const DefaultType = "default"
 
 type Default struct{}
 
@@ -14,5 +14,9 @@ func (d Default) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpeci
 }
 
 func (d Default) String() string {
-	return defaultName
+	return DefaultType
+}
+
+func (d Default) Type() string {
+	return DefaultType
 }
diff --git a/pkg/section/dot.go b/pkg/section/dot.go
index 5155b20..8112eeb 100644
--- a/pkg/section/dot.go
+++ b/pkg/section/dot.go
@@ -7,6 +7,8 @@ import (
 
 type Dot struct{}
 
+const DotType = "dot"
+
 func (d Dot) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
 	if spec.Name == "." {
 		return specificity.NameMatch{}
@@ -15,5 +17,9 @@ func (d Dot) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecifici
 }
 
 func (d Dot) String() string {
-	return "dot"
+	return DotType
+}
+
+func (d Dot) Type() string {
+	return DotType
 }
diff --git a/pkg/section/newline.go b/pkg/section/newline.go
index e83e30c..4bff91b 100644
--- a/pkg/section/newline.go
+++ b/pkg/section/newline.go
@@ -16,3 +16,7 @@ func (n NewLine) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpeci
 func (n NewLine) String() string {
 	return newLineName
 }
+
+func (n NewLine) Type() string {
+	return newLineName
+}
diff --git a/pkg/section/prefix.go b/pkg/section/prefix.go
index d6ec0e4..92ef963 100644
--- a/pkg/section/prefix.go
+++ b/pkg/section/prefix.go
@@ -12,6 +12,8 @@ type Custom struct {
 	Prefix string
 }
 
+const CustomType = "custom"
+
 func (c Custom) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecificity {
 	if strings.HasPrefix(spec.Path, c.Prefix) {
 		return specificity.Match{Length: len(c.Prefix)}
@@ -22,3 +24,7 @@ func (c Custom) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpecif
 func (c Custom) String() string {
 	return fmt.Sprintf("prefix(%s)", c.Prefix)
 }
+
+func (c Custom) Type() string {
+	return CustomType
+}
diff --git a/pkg/section/section.go b/pkg/section/section.go
index 55b641e..cc0a43f 100644
--- a/pkg/section/section.go
+++ b/pkg/section/section.go
@@ -12,6 +12,9 @@ type Section interface {
 
 	// String Implements the stringer interface
 	String() string
+
+	// return section type
+	Type() string
 }
 
 type SectionList []Section
diff --git a/pkg/section/standard.go b/pkg/section/standard.go
index 67068eb..26c7e9d 100644
--- a/pkg/section/standard.go
+++ b/pkg/section/standard.go
@@ -5,7 +5,7 @@ import (
 	"github.com/daixiang0/gci/pkg/specificity"
 )
 
-const StandardName = "standard"
+const StandardType = "standard"
 
 type Standard struct{}
 
@@ -17,7 +17,11 @@ func (s Standard) MatchSpecificity(spec *parse.GciImports) specificity.MatchSpec
 }
 
 func (s Standard) String() string {
-	return StandardName
+	return StandardType
+}
+
+func (s Standard) Type() string {
+	return StandardType
 }
 
 func isStandard(pkg string) bool {


Test patch:
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index f63db48..46de31c 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -14,7 +14,6 @@ var testFilesPath = "../gci/internal/testdata"
 func TestInitGciConfigFromEmptyYAML(t *testing.T) {
 	gciCfg, err := InitializeGciConfigFromYAML(path.Join(testFilesPath, "defaultValues.cfg.yaml"))
 	assert.NoError(t, err)
-	_ = gciCfg
 	assert.Equal(t, section.DefaultSections(), gciCfg.Sections)
 	assert.Equal(t, section.DefaultSectionSeparators(), gciCfg.SectionSeparators)
 	assert.False(t, gciCfg.Debug)
@@ -25,9 +24,30 @@ func TestInitGciConfigFromEmptyYAML(t *testing.T) {
 func TestInitGciConfigFromYAML(t *testing.T) {
 	gciCfg, err := InitializeGciConfigFromYAML(path.Join(testFilesPath, "configTest.cfg.yaml"))
 	assert.NoError(t, err)
-	_ = gciCfg
 	assert.Equal(t, section.SectionList{section.Default{}}, gciCfg.Sections)
 	assert.False(t, gciCfg.Debug)
 	assert.True(t, gciCfg.SkipGenerated)
 	assert.False(t, gciCfg.CustomOrder)
 }
+
+// the custom sections sort alphabetically as default.
+func TestParseOrder(t *testing.T) {
+	cfg := YamlConfig{
+		SectionStrings: []string{"default", "prefix(github/daixiang0/gci)", "prefix(github/daixiang0/gai)"},
+	}
+	gciCfg, err := cfg.Parse()
+	assert.NoError(t, err)
+	assert.Equal(t, section.SectionList{section.Default{}, section.Custom{Prefix: "github/daixiang0/gai"}, section.Custom{Prefix: "github/daixiang0/gci"}}, gciCfg.Sections)
+}
+
+func TestParseCustomOrder(t *testing.T) {
+	cfg := YamlConfig{
+		SectionStrings: []string{"default", "prefix(github/daixiang0/gci)", "prefix(github/daixiang0/gai)"},
+		Cfg: BoolConfig{
+			CustomOrder: true,
+		},
+	}
+	gciCfg, err := cfg.Parse()
+	assert.NoError(t, err)
+	assert.Equal(t, section.SectionList{section.Default{}, section.Custom{Prefix: "github/daixiang0/gci"}, section.Custom{Prefix: "github/daixiang0/gai"}}, gciCfg.Sections)
+}
diff --git a/pkg/gci/internal/testdata/mismatch-section.cfg.yaml b/pkg/gci/internal/testdata/mismatch-section.cfg.yaml
new file mode 100644
index 0000000..be67ca2
--- /dev/null
+++ b/pkg/gci/internal/testdata/mismatch-section.cfg.yaml
@@ -0,0 +1,5 @@
+sections:
+  - Standard
+  - Default
+  - Prefix(github.com/daixiang0)
+  - Prefix(github.com/daixiang0/gci)
diff --git a/pkg/gci/internal/testdata/mismatch-section.in.go b/pkg/gci/internal/testdata/mismatch-section.in.go
new file mode 100644
index 0000000..89de7a0
--- /dev/null
+++ b/pkg/gci/internal/testdata/mismatch-section.in.go
@@ -0,0 +1,8 @@
+package main
+import (
+	"fmt"
+
+	g "github.com/golang"
+
+	"github.com/daixiang0/gci"
+)
diff --git a/pkg/gci/internal/testdata/mismatch-section.out.go b/pkg/gci/internal/testdata/mismatch-section.out.go
new file mode 100644
index 0000000..89de7a0
--- /dev/null
+++ b/pkg/gci/internal/testdata/mismatch-section.out.go
@@ -0,0 +1,8 @@
+package main
+import (
+	"fmt"
+
+	g "github.com/golang"
+
+	"github.com/daixiang0/gci"
+)