add tagalign linter (#3709)
This commit is contained in:
parent
69f929b227
commit
134f2e0491
@ -1739,6 +1739,39 @@ linters-settings:
|
||||
# Default: ["200", "400", "404", "500"]
|
||||
http-status-code-whitelist: [ "200", "400", "404", "500" ]
|
||||
|
||||
tagalign:
|
||||
# Align and sort can be used together or separately.
|
||||
#
|
||||
# Whether enable align. If true, the struct tags will be aligned.
|
||||
# eg:
|
||||
# type FooBar struct {
|
||||
# Bar string `json:"bar" validate:"required"`
|
||||
# FooFoo int8 `json:"foo_foo" validate:"required"`
|
||||
# }
|
||||
# will be formatted to:
|
||||
# type FooBar struct {
|
||||
# Bar string `json:"bar" validate:"required"`
|
||||
# FooFoo int8 `json:"foo_foo" validate:"required"`
|
||||
# }
|
||||
# Default: true.
|
||||
align: false
|
||||
# Whether enable tags sort.
|
||||
# If true, the tags will be sorted by name in ascending order.
|
||||
# eg: `xml:"bar" json:"bar" validate:"required"` -> `json:"bar" validate:"required" xml:"bar"`
|
||||
# Default: true
|
||||
sort: false
|
||||
# Specify the order of tags, the other tags will be sorted by name.
|
||||
# This option will be ignored if `sort` is false.
|
||||
# Default: []
|
||||
order:
|
||||
- json
|
||||
- yaml
|
||||
- yml
|
||||
- toml
|
||||
- mapstructure
|
||||
- binding
|
||||
- validate
|
||||
|
||||
tagliatelle:
|
||||
# Check the struct tag name case.
|
||||
case:
|
||||
@ -2118,6 +2151,7 @@ linters:
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- tagalign
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testableexamples
|
||||
@ -2229,6 +2263,7 @@ linters:
|
||||
- staticcheck
|
||||
- structcheck
|
||||
- stylecheck
|
||||
- tagalign
|
||||
- tagliatelle
|
||||
- tenv
|
||||
- testableexamples
|
||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.19
|
||||
require (
|
||||
4d63.com/gocheckcompilerdirectives v1.2.1
|
||||
4d63.com/gochecknoglobals v0.2.1
|
||||
github.com/4meepo/tagalign v1.2.2
|
||||
github.com/Abirdcfly/dupword v0.0.11
|
||||
github.com/Antonboom/errname v0.1.9
|
||||
github.com/Antonboom/nilnil v0.1.3
|
||||
|
2
go.sum
generated
2
go.sum
generated
@ -40,6 +40,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/4meepo/tagalign v1.2.2 h1:kQeUTkFTaBRtd/7jm8OKJl9iHk0gAO+TDFPHGSna0aw=
|
||||
github.com/4meepo/tagalign v1.2.2/go.mod h1:Q9c1rYMZJc9dPRkbQPpcBNCLEmY2njbAsXhQOZFE2dE=
|
||||
github.com/Abirdcfly/dupword v0.0.11 h1:z6v8rMETchZXUIuHxYNmlUAuKuB21PeaSymTed16wgU=
|
||||
github.com/Abirdcfly/dupword v0.0.11/go.mod h1:wH8mVGuf3CP5fsBTkfWwwwKTjDnVVCxtU8d8rgeVYXA=
|
||||
github.com/Antonboom/errname v0.1.9 h1:BZDX4r3l4TBZxZ2o2LNrlGxSHran4d1u4veZdoORTT4=
|
||||
|
@ -110,6 +110,11 @@ var defaultLintersSettings = LintersSettings{
|
||||
Ignore: "",
|
||||
Qualified: false,
|
||||
},
|
||||
TagAlign: TagAlignSettings{
|
||||
Align: true,
|
||||
Sort: true,
|
||||
Order: nil,
|
||||
},
|
||||
Testpackage: TestpackageSettings{
|
||||
SkipRegexp: `(export|internal)_test\.go`,
|
||||
AllowPackages: []string{"main"},
|
||||
@ -203,6 +208,7 @@ type LintersSettings struct {
|
||||
Staticcheck StaticCheckSettings
|
||||
Structcheck StructCheckSettings
|
||||
Stylecheck StaticCheckSettings
|
||||
TagAlign TagAlignSettings
|
||||
Tagliatelle TagliatelleSettings
|
||||
Tenv TenvSettings
|
||||
Testpackage TestpackageSettings
|
||||
@ -655,6 +661,12 @@ type StructCheckSettings struct {
|
||||
CheckExportedFields bool `mapstructure:"exported-fields"`
|
||||
}
|
||||
|
||||
type TagAlignSettings struct {
|
||||
Align bool `mapstructure:"align"`
|
||||
Sort bool `mapstructure:"sort"`
|
||||
Order []string `mapstructure:"order"`
|
||||
}
|
||||
|
||||
type TagliatelleSettings struct {
|
||||
Case struct {
|
||||
Rules map[string]string
|
||||
|
70
pkg/golinters/tagalign.go
Normal file
70
pkg/golinters/tagalign.go
Normal file
@ -0,0 +1,70 @@
|
||||
package golinters
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/4meepo/tagalign"
|
||||
"golang.org/x/tools/go/analysis"
|
||||
|
||||
"github.com/golangci/golangci-lint/pkg/config"
|
||||
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
|
||||
"github.com/golangci/golangci-lint/pkg/lint/linter"
|
||||
"github.com/golangci/golangci-lint/pkg/result"
|
||||
)
|
||||
|
||||
func NewTagAlign(settings *config.TagAlignSettings) *goanalysis.Linter {
|
||||
var mu sync.Mutex
|
||||
var resIssues []goanalysis.Issue
|
||||
|
||||
options := []tagalign.Option{tagalign.WithMode(tagalign.GolangciLintMode)}
|
||||
|
||||
if settings != nil {
|
||||
options = append(options, tagalign.WithAlign(settings.Align))
|
||||
|
||||
if settings.Sort || len(settings.Order) > 0 {
|
||||
options = append(options, tagalign.WithSort(settings.Order...))
|
||||
}
|
||||
}
|
||||
|
||||
analyzer := tagalign.NewAnalyzer(options...)
|
||||
analyzer.Run = func(pass *analysis.Pass) (any, error) {
|
||||
taIssues := tagalign.Run(pass, options...)
|
||||
|
||||
issues := make([]goanalysis.Issue, len(taIssues))
|
||||
for i, issue := range taIssues {
|
||||
report := &result.Issue{
|
||||
FromLinter: analyzer.Name,
|
||||
Pos: issue.Pos,
|
||||
Text: issue.Message,
|
||||
Replacement: &result.Replacement{
|
||||
Inline: &result.InlineFix{
|
||||
StartCol: issue.InlineFix.StartCol,
|
||||
Length: issue.InlineFix.Length,
|
||||
NewString: issue.InlineFix.NewString,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
issues[i] = goanalysis.NewIssue(report, pass)
|
||||
}
|
||||
|
||||
if len(issues) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
mu.Lock()
|
||||
resIssues = append(resIssues, issues...)
|
||||
mu.Unlock()
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return goanalysis.NewLinter(
|
||||
analyzer.Name,
|
||||
analyzer.Doc,
|
||||
[]*analysis.Analyzer{analyzer},
|
||||
nil,
|
||||
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
|
||||
return resIssues
|
||||
}).WithLoadMode(goanalysis.LoadModeSyntax)
|
||||
}
|
@ -165,6 +165,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
staticcheckCfg *config.StaticCheckSettings
|
||||
structcheckCfg *config.StructCheckSettings
|
||||
stylecheckCfg *config.StaticCheckSettings
|
||||
tagalignCfg *config.TagAlignSettings
|
||||
tagliatelleCfg *config.TagliatelleSettings
|
||||
tenvCfg *config.TenvSettings
|
||||
testpackageCfg *config.TestpackageSettings
|
||||
@ -244,6 +245,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
staticcheckCfg = &m.cfg.LintersSettings.Staticcheck
|
||||
structcheckCfg = &m.cfg.LintersSettings.Structcheck
|
||||
stylecheckCfg = &m.cfg.LintersSettings.Stylecheck
|
||||
tagalignCfg = &m.cfg.LintersSettings.TagAlign
|
||||
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
|
||||
tenvCfg = &m.cfg.LintersSettings.Tenv
|
||||
testpackageCfg = &m.cfg.LintersSettings.Testpackage
|
||||
@ -777,6 +779,12 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
|
||||
WithPresets(linter.PresetStyle).
|
||||
WithURL("https://github.com/dominikh/go-tools/tree/master/stylecheck"),
|
||||
|
||||
linter.NewConfig(golinters.NewTagAlign(tagalignCfg)).
|
||||
WithSince("v1.53.0").
|
||||
WithPresets(linter.PresetStyle, linter.PresetFormatting).
|
||||
WithAutoFix().
|
||||
WithURL("https://github.com/4meepo/tagalign"),
|
||||
|
||||
linter.NewConfig(golinters.NewTagliatelle(tagliatelleCfg)).
|
||||
WithSince("v1.40.0").
|
||||
WithPresets(linter.PresetStyle).
|
||||
|
3
test/testdata/configs/tagalign_align_only.yml
vendored
Normal file
3
test/testdata/configs/tagalign_align_only.yml
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
linters-settings:
|
||||
tagalign:
|
||||
sort: false
|
7
test/testdata/configs/tagalign_order_only.yml
vendored
Normal file
7
test/testdata/configs/tagalign_order_only.yml
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
linters-settings:
|
||||
tagalign:
|
||||
align: false
|
||||
order:
|
||||
- "xml"
|
||||
- "json"
|
||||
- "yaml"
|
4
test/testdata/configs/tagalign_sort_only.yml
vendored
Normal file
4
test/testdata/configs/tagalign_sort_only.yml
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
linters-settings:
|
||||
tagalign:
|
||||
align: false
|
||||
sort: true
|
15
test/testdata/tagalign.go
vendored
Normal file
15
test/testdata/tagalign.go
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//golangcitest:args -Etagalign
|
||||
package testdata
|
||||
|
||||
import "time"
|
||||
|
||||
type TagAlignExampleAlignSort struct {
|
||||
Foo time.Duration `json:"foo,omitempty" yaml:"foo" xml:"foo" binding:"required" gorm:"column:foo" zip:"foo" validate:"required"` // want `binding:"required" gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
Bar int `validate:"required" yaml:"bar" xml:"bar" binding:"required" json:"bar,omitempty" gorm:"column:bar" zip:"bar" ` // want `binding:"required" gorm:"column:bar" json:"bar,omitempty" validate:"required" xml:"bar" yaml:"bar" zip:"bar"`
|
||||
FooBar int `gorm:"column:fooBar" validate:"required" xml:"fooBar" binding:"required" json:"fooBar,omitempty" zip:"fooBar" yaml:"fooBar"` // want `binding:"required" gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||
}
|
||||
|
||||
type TagAlignExampleAlignSort2 struct {
|
||||
Foo int ` xml:"foo" json:"foo,omitempty" yaml:"foo" zip:"foo" binding:"required" gorm:"column:foo" validate:"required"` // want `binding:"required" gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
Bar int `validate:"required" gorm:"column:bar" yaml:"bar" xml:"bar" binding:"required" json:"bar" zip:"bar" ` // want `binding:"required" gorm:"column:bar" json:"bar" validate:"required" xml:"bar" yaml:"bar" zip:"bar"`
|
||||
}
|
31
test/testdata/tagalign_align_only.go
vendored
Normal file
31
test/testdata/tagalign_align_only.go
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
//golangcitest:args -Etagalign
|
||||
//golangcitest:config_path testdata/configs/tagalign_align_only.yml
|
||||
package testdata
|
||||
|
||||
import "time"
|
||||
|
||||
type TagAlignExampleAlignOnlyKO struct {
|
||||
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"` // want `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
FooBar struct{} `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"` // want `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"`
|
||||
FooFoo struct {
|
||||
Foo int `json:"foo" yaml:"foo"` // want `json:"foo" yaml:"foo"`
|
||||
Bar int `yaml:"bar" json:"bar"` // want `yaml:"bar" json:"bar"`
|
||||
BarBar string `json:"barBar" yaml:"barBar"`
|
||||
} `xml:"fooFoo" json:"fooFoo"`
|
||||
NoTag struct{}
|
||||
BarBar struct{} `json:"barBar,omitempty" gorm:"column:barBar" yaml:"barBar" xml:"barBar" zip:"barBar"`
|
||||
Boo struct{} `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"` // want `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"`
|
||||
}
|
||||
|
||||
type TagAlignExampleAlignOnlyOK struct {
|
||||
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
FooBar struct{} `gorm:"column:fooBar" zip:"fooBar" json:"fooBar,omitempty" xml:"fooBar" yaml:"fooBar"`
|
||||
FooFoo struct {
|
||||
Foo int `json:"foo" yaml:"foo"`
|
||||
Bar int `yaml:"bar" json:"bar"`
|
||||
BarBar string `json:"barBar" yaml:"barBar"`
|
||||
} `xml:"fooFoo" json:"fooFoo"`
|
||||
NoTag struct{}
|
||||
BarBar struct{} `json:"barBar,omitempty" gorm:"column:barBar" yaml:"barBar" xml:"barBar" zip:"barBar"`
|
||||
Boo struct{} `gorm:"column:boo" json:"boo,omitempty" xml:"boo" yaml:"boo" zip:"boo"`
|
||||
}
|
15
test/testdata/tagalign_order_only.go
vendored
Normal file
15
test/testdata/tagalign_order_only.go
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//golangcitest:args -Etagalign
|
||||
//golangcitest:config_path testdata/configs/tagalign_order_only.yml
|
||||
package testdata
|
||||
|
||||
import "time"
|
||||
|
||||
type TagAlignExampleOrderOnlyKO struct {
|
||||
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" zip:"foo" gorm:"column:foo" validate:"required"` // want `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"`
|
||||
FooBar struct{} `gorm:"column:fooBar" validate:"required" zip:"fooBar" xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar"` // want `xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar" gorm:"column:fooBar" validate:"required" zip:"fooBar"`
|
||||
}
|
||||
|
||||
type TagAlignExampleOrderOnlyOK struct {
|
||||
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"`
|
||||
FooBar struct{} `xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar" gorm:"column:fooBar" validate:"required" zip:"fooBar"`
|
||||
}
|
15
test/testdata/tagalign_sort_only.go
vendored
Normal file
15
test/testdata/tagalign_sort_only.go
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
//golangcitest:args -Etagalign
|
||||
//golangcitest:config_path testdata/configs/tagalign_sort_only.yml
|
||||
package testdata
|
||||
|
||||
import "time"
|
||||
|
||||
type TagAlignExampleSortOnlyKO struct {
|
||||
Foo time.Time `xml:"foo" json:"foo,omitempty" yaml:"foo" gorm:"column:foo" validate:"required" zip:"foo"` // want `gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
FooBar struct{} `gorm:"column:fooBar" validate:"required" zip:"fooBar" xml:"fooBar" json:"fooBar,omitempty" yaml:"fooBar"` // want `gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||
}
|
||||
|
||||
type TagAlignExampleSortOnlyOK struct {
|
||||
Foo time.Time `gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"`
|
||||
FooBar struct{} `gorm:"column:fooBar" json:"fooBar,omitempty" validate:"required" xml:"fooBar" yaml:"fooBar" zip:"fooBar"`
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user