diff --git a/formatter.go b/formatter.go index 511e3a822..1074a3bf5 100644 --- a/formatter.go +++ b/formatter.go @@ -12,6 +12,8 @@ import ( "sort" "strings" "text/tabwriter" + + "golang.org/x/tools/imports" ) // Check of @Param @Success @Failure @Response @Header @@ -68,8 +70,11 @@ func (f *Formatter) Format(fileName string, contents []byte) ([]byte, error) { for _, comment := range ast.Comments { formatFuncDoc(fileSet, comment.List, &edits) } - - return edits.apply(contents), nil + formatted, err := imports.Process(fileName, edits.apply(contents), nil) + if err != nil { + return nil, err + } + return formatted, nil } type edit struct { diff --git a/formatter_test.go b/formatter_test.go index 4c650a986..0e02fabe0 100644 --- a/formatter_test.go +++ b/formatter_test.go @@ -64,77 +64,80 @@ func Test_FormatMain(t *testing.T) { func main() {}` want := `package main - // @title Swagger Example API - // @version 1.0 - // @description This is a sample server Petstore server. - // @termsOfService http://swagger.io/terms/ - - // @contact.name API Support - // @contact.url http://www.swagger.io/support - // @contact.email support@swagger.io - - // @license.name Apache 2.0 - // @license.url http://www.apache.org/licenses/LICENSE-2.0.html - - // @host petstore.swagger.io - // @BasePath /v2 - - // @securityDefinitions.basic BasicAuth - - // @securityDefinitions.apikey ApiKeyAuth - // @in header - // @name Authorization - - // @securitydefinitions.oauth2.application OAuth2Application - // @tokenUrl https://example.com/oauth/token - // @scope.write Grants write access - // @scope.admin Grants read and write access to administrative information - - // @securitydefinitions.oauth2.implicit OAuth2Implicit - // @authorizationurl https://example.com/oauth/authorize - // @scope.write Grants write access - // @scope.admin Grants read and write access to administrative information - - // @securitydefinitions.oauth2.password OAuth2Password - // @tokenUrl https://example.com/oauth/token - // @scope.read Grants read access - // @scope.write Grants write access - // @scope.admin Grants read and write access to administrative information - - // @securitydefinitions.oauth2.accessCode OAuth2AccessCode - // @tokenUrl https://example.com/oauth/token - // @authorizationurl https://example.com/oauth/authorize - // @scope.admin Grants read and write access to administrative information - func main() {}` + +// @title Swagger Example API +// @version 1.0 +// @description This is a sample server Petstore server. +// @termsOfService http://swagger.io/terms/ + +// @contact.name API Support +// @contact.url http://www.swagger.io/support +// @contact.email support@swagger.io + +// @license.name Apache 2.0 +// @license.url http://www.apache.org/licenses/LICENSE-2.0.html + +// @host petstore.swagger.io +// @BasePath /v2 + +// @securityDefinitions.basic BasicAuth + +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name Authorization + +// @securitydefinitions.oauth2.application OAuth2Application +// @tokenUrl https://example.com/oauth/token +// @scope.write Grants write access +// @scope.admin Grants read and write access to administrative information + +// @securitydefinitions.oauth2.implicit OAuth2Implicit +// @authorizationurl https://example.com/oauth/authorize +// @scope.write Grants write access +// @scope.admin Grants read and write access to administrative information + +// @securitydefinitions.oauth2.password OAuth2Password +// @tokenUrl https://example.com/oauth/token +// @scope.read Grants read access +// @scope.write Grants write access +// @scope.admin Grants read and write access to administrative information + +// @securitydefinitions.oauth2.accessCode OAuth2AccessCode +// @tokenUrl https://example.com/oauth/token +// @authorizationurl https://example.com/oauth/authorize +// @scope.admin Grants read and write access to administrative information +func main() {} +` testFormat(t, "main.go", contents, want) } func Test_FormatMultipleFunctions(t *testing.T) { contents := `package main - // @Produce json - // @Success 200 {object} string - // @Failure 400 {object} string +// @Produce json +// @Success 200 {object} string +// @Failure 400 {object} string func A() {} - // @Description Description of B. - // @Produce json - // @Success 200 {array} string - // @Failure 400 {object} string +// @Description Description of B. +// @Produce json +// @Success 200 {array} string +// @Failure 400 {object} string func B() {}` want := `package main - // @Produce json - // @Success 200 {object} string - // @Failure 400 {object} string - func A() {} +// @Produce json +// @Success 200 {object} string +// @Failure 400 {object} string +func A() {} - // @Description Description of B. - // @Produce json - // @Success 200 {array} string - // @Failure 400 {object} string - func B() {}` +// @Description Description of B. +// @Produce json +// @Success 200 {array} string +// @Failure 400 {object} string +func B() {} +` testFormat(t, "main.go", contents, want) } @@ -142,76 +145,86 @@ func Test_FormatMultipleFunctions(t *testing.T) { func Test_FormatApi(t *testing.T) { contents := `package api - import "net/http" - - // @Summary Add a new pet to the store - // @Description get string by ID - // @ID get-string-by-int - // @Accept json - // @Produce json - // @Param some_id path int true "Some ID" Format(int64) - // @Param some_id body web.Pet true "Some ID" - // @Success 200 {string} string "ok" - // @Failure 400 {object} web.APIError "We need ID!!" - // @Failure 404 {object} web.APIError "Can not find ID" - // @Router /testapi/get-string-by-int/{some_id} [get] +import "net/http" + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @Accept json +// @Produce json +// @Param some_id path int true "Some ID" Format(int64) +// @Param some_id body web.Pet true "Some ID" +// @Success 200 {string} string "ok" +// @Failure 400 {object} web.APIError "We need ID!!" +// @Failure 404 {object} web.APIError "Can not find ID" +// @Router /testapi/get-string-by-int/{some_id} [get] func GetStringByInt(w http.ResponseWriter, r *http.Request) {}` want := `package api - import "net/http" - - // @Summary Add a new pet to the store - // @Description get string by ID - // @ID get-string-by-int - // @Accept json - // @Produce json - // @Param some_id path int true "Some ID" Format(int64) - // @Param some_id body web.Pet true "Some ID" - // @Success 200 {string} string "ok" - // @Failure 400 {object} web.APIError "We need ID!!" - // @Failure 404 {object} web.APIError "Can not find ID" - // @Router /testapi/get-string-by-int/{some_id} [get] - func GetStringByInt(w http.ResponseWriter, r *http.Request) {}` +import "net/http" + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @Accept json +// @Produce json +// @Param some_id path int true "Some ID" Format(int64) +// @Param some_id body web.Pet true "Some ID" +// @Success 200 {string} string "ok" +// @Failure 400 {object} web.APIError "We need ID!!" +// @Failure 404 {object} web.APIError "Can not find ID" +// @Router /testapi/get-string-by-int/{some_id} [get] +func GetStringByInt(w http.ResponseWriter, r *http.Request) {} +` testFormat(t, "api.go", contents, want) } func Test_NonSwagComment(t *testing.T) { contents := `package api - // @Summary Add a new pet to the store - // @Description get string by ID - // @ID get-string-by-int - // @ Accept json - // This is not a @swag comment` + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @ Accept json +// This is not a @swag comment` want := `package api - // @Summary Add a new pet to the store - // @Description get string by ID - // @ID get-string-by-int - // @ Accept json - // This is not a @swag comment` + +// @Summary Add a new pet to the store +// @Description get string by ID +// @ID get-string-by-int +// @ Accept json +// This is not a @swag comment +` testFormat(t, "non_swag.go", contents, want) } func Test_EmptyComment(t *testing.T) { contents := `package empty - // @Summary Add a new pet to the store - // @Description ` + +// @Summary Add a new pet to the store +// @Description ` want := `package empty - // @Summary Add a new pet to the store - // @Description` + +// @Summary Add a new pet to the store +// @Description +` testFormat(t, "empty.go", contents, want) } func Test_AlignAttribute(t *testing.T) { contents := `package align - // @Summary Add a new pet to the store - // @Description Description` + +// @Summary Add a new pet to the store +// @Description Description` want := `package align - // @Summary Add a new pet to the store - // @Description Description` + +// @Summary Add a new pet to the store +// @Description Description +` testFormat(t, "align.go", contents, want) diff --git a/go.mod b/go.mod index c8f74875e..3a40bc142 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/russross/blackfriday/v2 v2.0.1 // indirect github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect + golang.org/x/mod v0.9.0 // indirect golang.org/x/net v0.23.0 // indirect golang.org/x/sys v0.18.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index 4c16e3b8a..98185a381 100644 --- a/go.sum +++ b/go.sum @@ -48,6 +48,7 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=