Skip to content

Commit

Permalink
[ISSUE-104] Separated groups for "_" and "." imports (#138)
Browse files Browse the repository at this point in the history
* [ISSUE-104] Separated groups for "_" and "." imports
  • Loading branch information
incu6us authored Oct 13, 2023
1 parent 607f2e6 commit 680c19a
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 88 deletions.
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,9 @@ Usage of goimports-reviser:
std - std import group;
general - libs for general purpose;
company - inter-org or your company libs(if you set '-company-prefixes'-option, then 4th group will be split separately. In other case, it will be the part of general purpose libs);
project - your local project dependencies.
project - your local project dependencies;
blanked - imports with "_" alias;
dotted - imports with "." alias;
Optional parameter. (default "std,general,company,project")
-list-diff
Option will list files whose formatting differs from goimports-reviser. Optional parameter.
Expand Down Expand Up @@ -178,6 +180,42 @@ import (
)
```

### Example with `-imports-order std,general,company,project,blanked,dotted`-option

Before usage:

```go
package testdata // goimports-reviser/testdata

import (
_ "github.com/pkg1"
. "github.com/pkg2"
"fmt" //fmt package
"golang.org/x/exp/slices" //custom package
"github.com/incu6us/goimports-reviser/pkg" // this is a company package which is not a part of the project, but is a part of your organization
"goimports-reviser/pkg"
)
```

After usage:
```go
package testdata // goimports-reviser/testdata

import (
"fmt" // fmt package

"golang.org/x/exp/slices" // custom package

"github.com/incu6us/goimports-reviser/pkg" // this is a company package which is not a part of the project, but is a part of your organization

"goimports-reviser/pkg"

_ "github.com/pkg1"

. "github.com/pkg2"
)
```

### Example with `-format`-option

Before usage:
Expand Down
113 changes: 46 additions & 67 deletions reviser/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type SourceFile struct {
shouldUseAliasForVersionSuffix bool
shouldFormatCode bool
shouldSkipAutoGenerated bool
hasSeparateSideEffectGroup bool
companyPackagePrefixes []string
importsOrders ImportsOrders

Expand Down Expand Up @@ -85,7 +86,7 @@ func (f *SourceFile) Fix(options ...SourceFileOption) ([]byte, bool, error) {
return nil, false, err
}

stdImports, generalImports, projectLocalPkgs, projectImports := groupImports(
groups := f.groupImports(
f.projectName,
f.companyPackagePrefixes,
importsWithMetadata,
Expand All @@ -96,7 +97,7 @@ func (f *SourceFile) Fix(options ...SourceFileOption) ([]byte, bool, error) {
pf.Decls = decls
}

f.fixImports(pf, stdImports, generalImports, projectLocalPkgs, projectImports, importsWithMetadata)
f.fixImports(pf, groups, importsWithMetadata)

f.formatDecls(pf)

Expand Down Expand Up @@ -157,21 +158,32 @@ func fixCommentGroup(commentGroup *ast.CommentGroup) *ast.CommentGroup {
return formattedDoc
}

func groupImports(
func (f *SourceFile) groupImports(
projectName string,
localPkgPrefixes []string,
importsWithMetadata map[string]*commentsMetadata,
) ([]string, []string, []string, []string) {
) *groupsImports {
var (
stdImports []string
projectImports []string
projectLocalPkgs []string
generalImports []string
blankedImports []string
dottedImports []string
)

for imprt := range importsWithMetadata {
pkgWithoutAlias := skipPackageAlias(imprt)
if f.importsOrders.hasBlankedImportOrder() && strings.HasPrefix(imprt, "_") {
blankedImports = append(blankedImports, imprt)
continue
}

if f.importsOrders.hasDottedImportOrder() && strings.HasPrefix(imprt, ".") {
dottedImports = append(dottedImports, imprt)
continue
}

pkgWithoutAlias := skipPackageAlias(imprt)
if _, ok := std.StdPackages[pkgWithoutAlias]; ok {
stdImports = append(stdImports, imprt)
continue
Expand Down Expand Up @@ -202,8 +214,20 @@ func groupImports(
sort.Strings(generalImports)
sort.Strings(projectLocalPkgs)
sort.Strings(projectImports)

return stdImports, generalImports, projectLocalPkgs, projectImports
sort.Strings(blankedImports)
sort.Strings(dottedImports)

result := &groupsImports{
common: &common{
std: stdImports,
general: generalImports,
company: projectLocalPkgs,
project: projectImports,
},
blanked: blankedImports,
dotted: dottedImports,
}
return result
}

func skipPackageAlias(pkg string) string {
Expand Down Expand Up @@ -237,7 +261,7 @@ func isSingleCgoImport(dd *ast.GenDecl) bool {

func (f *SourceFile) fixImports(
file *ast.File,
stdImports, generalImports, projectLocalPkgs, projectImports []string,
groups *groupsImports,
commentsMetadata map[string]*commentsMetadata,
) {
var importsPositions []*importPosition
Expand All @@ -258,8 +282,8 @@ func (f *SourceFile) fixImports(
},
)

one, two, three, four := f.importsOrders.sortImportsByOrder(stdImports, generalImports, projectLocalPkgs, projectImports)
dd.Specs = rebuildImports(dd.Tok, commentsMetadata, one, two, three, four)
imports := f.importsOrders.sortImportsByOrder(groups)
dd.Specs = rebuildImports(dd.Tok, commentsMetadata, imports)
}

clearImportDocs(file, importsPositions)
Expand All @@ -275,8 +299,10 @@ func (f *SourceFile) fixImports(
// to
// -----
// import (
// "fmt"
//
// "fmt"
// "io"
//
// )
func hasMultipleImportDecls(f *ast.File) ([]ast.Decl, bool) {
importSpecs := make([]ast.Spec, 0, len(f.Imports))
Expand Down Expand Up @@ -349,71 +375,24 @@ func removeEmptyImportNode(f *ast.File) {
}
}

func rebuildImports(
tok token.Token,
commentsMetadata map[string]*commentsMetadata,
firstImportGroup []string,
secondImportsGroup []string,
thirdImportsGroup []string,
fourthImportGroup []string,
) []ast.Spec {
func rebuildImports(tok token.Token, commentsMetadata map[string]*commentsMetadata, imports [][]string) []ast.Spec {
var specs []ast.Spec

linesCounter := len(firstImportGroup)
for _, imprt := range firstImportGroup {
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: importWithComment(imprt, commentsMetadata), Kind: tok},
}
specs = append(specs, spec)

linesCounter--

if linesCounter == 0 && (len(secondImportsGroup) > 0 || len(thirdImportsGroup) > 0 || len(fourthImportGroup) > 0) {
spec = &ast.ImportSpec{Path: &ast.BasicLit{Value: "", Kind: token.STRING}}

specs = append(specs, spec)
}
}

linesCounter = len(secondImportsGroup)
for _, imprt := range secondImportsGroup {
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: importWithComment(imprt, commentsMetadata), Kind: tok},
}
specs = append(specs, spec)

linesCounter--

if linesCounter == 0 && (len(thirdImportsGroup) > 0 || len(fourthImportGroup) > 0) {
spec = &ast.ImportSpec{Path: &ast.BasicLit{Value: "", Kind: token.STRING}}

amountOfGroups := len(imports)
for i, group := range imports {
for _, imprt := range group {
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: importWithComment(imprt, commentsMetadata), Kind: tok},
}
specs = append(specs, spec)
}
}

linesCounter = len(thirdImportsGroup)
for _, imprt := range thirdImportsGroup {
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: importWithComment(imprt, commentsMetadata), Kind: tok},
}
specs = append(specs, spec)

linesCounter--

if linesCounter == 0 && len(fourthImportGroup) > 0 {
spec = &ast.ImportSpec{Path: &ast.BasicLit{Value: "", Kind: token.STRING}}
if len(group) != 0 && i != amountOfGroups-1 {
spec := &ast.ImportSpec{Path: &ast.BasicLit{Value: "", Kind: token.STRING}}

specs = append(specs, spec)
}
}

for _, imprt := range fourthImportGroup {
spec := &ast.ImportSpec{
Path: &ast.BasicLit{Value: importWithComment(imprt, commentsMetadata), Kind: tok},
}
specs = append(specs, spec)
}

return specs
}

Expand Down
80 changes: 79 additions & 1 deletion reviser/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -708,6 +708,51 @@ import (
"log"
)
// nolint:gomnd
`,
wantChange: true,
wantErr: false,
},
{
name: "success project,company,general,std,blanked,dotted",
args: args{
projectName: "github.com/incu6us/goimports-reviser",
filePath: "./testdata/example.go",
importsOrder: "project,company,general,std,blanked,dotted",
fileContent: `package testdata
import (
"log"
"github.com/incu6us/goimports-reviser/testdata/innderpkg"
"bytes"
. "io"
"golang.org/x/exp/slices"
_ "fmt"
)
// nolint:gomnd
`,
},
want: `package testdata
import (
"github.com/incu6us/goimports-reviser/testdata/innderpkg"
"golang.org/x/exp/slices"
"bytes"
"log"
_ "fmt"
. "io"
)
// nolint:gomnd
`,
wantChange: true,
Expand Down Expand Up @@ -960,6 +1005,39 @@ func main() {
wantChange: true,
wantErr: false,
},
{
name: "skip blanked and dotted import names",
args: args{
projectName: "github.com/incu6us/goimports-reviser",
filePath: "./testdata/example.go",
fileContent: `// Some comments are here
package testdata
import (
_ "fmt"
. "io"
)
// nolint:gomnd
func main() {
}
`,
},
want: `// Some comments are here
package testdata
import (
_ "fmt"
. "io"
)
// nolint:gomnd
func main() {
}
`,
wantChange: false,
wantErr: false,
},
{
name: `success with "C"`,
args: args{
Expand Down Expand Up @@ -1020,8 +1098,8 @@ func main() {
}

assert.NoError(t, err)
assert.Equal(t, tt.wantChange, hasChange)
assert.Equal(t, tt.want, string(got))
assert.Equal(t, tt.wantChange, hasChange)
})
}
}
Expand Down
Loading

0 comments on commit 680c19a

Please sign in to comment.