From 020378affad4f1a8ae0cd6ac4ba3711ffd399e52 Mon Sep 17 00:00:00 2001 From: Vyacheslav Pryimak Date: Mon, 5 Apr 2021 23:10:19 +0300 Subject: [PATCH] #42 Combine multiple import tokens to single (#48) #42 combine multiple import tokens to single --- go.sum | 2 -- reviser/reviser.go | 54 ++++++++++++++++++++++++++++++++++++++++- reviser/reviser_test.go | 31 ++++++++++++++++++++++- 3 files changed, 83 insertions(+), 4 deletions(-) diff --git a/go.sum b/go.sum index b4a94c4..fbac785 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -34,7 +33,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/reviser/reviser.go b/reviser/reviser.go index 32c25b6..096dd29 100644 --- a/reviser/reviser.go +++ b/reviser/reviser.go @@ -80,6 +80,11 @@ func Execute(projectName, filePath, localPkgPrefixes string, options ...Option) importsWithMetadata, ) + decls, ok := hasMultipleImportTokens(pf) + if ok { + pf.Decls = decls + } + fixImports(pf, stdImports, generalImports, projectLocalPkgs, projectImports, importsWithMetadata) fixedImportsContent, err := generateFile(fset, pf) @@ -188,7 +193,6 @@ func fixImports( commentsMetadata map[string]*commentsMetadata, ) { var importsPositions []*importPosition - for _, decl := range f.Decls { dd, ok := decl.(*ast.GenDecl) if !ok { @@ -213,6 +217,54 @@ func fixImports( removeEmptyImportNode(f) } +// hasMultipleImportTokens will return combined import tokens to single declaration +// +// Ex.: +// import "fmt" +// import "io" +// ----- +// to +// ----- +// import ( +// "fmt" +// "io" +// ) +func hasMultipleImportTokens(f *ast.File) ([]ast.Decl, bool) { + importSpecs := make([]ast.Spec, 0, len(f.Imports)) + for _, importSpec := range f.Imports { + importSpecs = append(importSpecs, importSpec) + } + + var hasMultipleImportTokens bool + decls := make([]ast.Decl, 0, len(f.Decls)) + for _, decl := range f.Decls { + dd, ok := decl.(*ast.GenDecl) + if !ok { + decls = append(decls, decl) + continue + } + + if dd.Tok != token.IMPORT { + decls = append(decls, dd) + continue + } + + if hasMultipleImportTokens { + storedGenDecl := decls[len(decls)-1].(*ast.GenDecl) + if storedGenDecl.Tok == token.IMPORT { + storedGenDecl.Rparen = dd.End() + } + continue + } + + dd.Specs = importSpecs + decls = append(decls, dd) + hasMultipleImportTokens = true + } + + return decls, hasMultipleImportTokens +} + func removeEmptyImportNode(f *ast.File) { var ( decls []ast.Decl diff --git a/reviser/reviser_test.go b/reviser/reviser_test.go index 1bd7039..b135ced 100644 --- a/reviser/reviser_test.go +++ b/reviser/reviser_test.go @@ -298,7 +298,6 @@ import ( wantChange: false, wantErr: false, }, - { name: "success no changes by imports and comments", args: args{ @@ -336,6 +335,36 @@ import ( wantChange: false, wantErr: false, }, + { + name: "success with multiple import statements", + args: args{ + projectName: "github.com/incu6us/goimports-reviser", + filePath: "./testdata/example.go", + fileContent: `package testdata + + import "sync" + import "testing" + + // yolo + import "fmt" + + + // not sure why this is here but we shall find out soon enough + import "io" +`, + }, + want: `package testdata + +import ( + "fmt" + "io" + "sync" + "testing" +) +`, + wantChange: true, + wantErr: false, + }, } for _, tt := range tests { if err := ioutil.WriteFile(tt.args.filePath, []byte(tt.args.fileContent), 0644); err != nil {