diff --git a/.github/workflows/main.yaml b/.github/workflows/main.yaml index 95f542f..a096302 100644 --- a/.github/workflows/main.yaml +++ b/.github/workflows/main.yaml @@ -6,13 +6,13 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 2 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v5 with: - go-version: '1.19' + go-version: stable - name: Run coverage run: go test -race -coverprofile=coverage.txt -covermode=atomic - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 \ No newline at end of file + uses: codecov/codecov-action@v3 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7d5d7f5..1aaf38a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,16 +15,15 @@ jobs: goreleaser: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - run: git fetch --force --tags - - uses: actions/setup-go@v4 + - uses: actions/setup-go@v5 with: go-version: stable # More assembly might be required: Docker logins, GPG, etc. It all depends # on your needs. - - uses: goreleaser/goreleaser-action@v4 + - uses: goreleaser/goreleaser-action@v6 with: # either 'goreleaser' (default) or 'goreleaser-pro': distribution: goreleaser diff --git a/.gitignore b/.gitignore index e37bb52..1c6218e 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ *.test .vscode +.idea/ # Output of the go coverage tool, specifically when used with LiteIDE *.out diff --git a/.goreleaser.yml b/.goreleaser.yml index e7b6f68..37dfec7 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,4 +1,4 @@ ---- +version: 2 project_name: tagalign release: @@ -29,4 +29,4 @@ builds: goarch: 386 - goos: freebsd goarch: arm64 - main: ./cmd/tagalign/ \ No newline at end of file + main: ./cmd/tagalign/ diff --git a/go.mod b/go.mod index 7abad10..86c035a 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/4meepo/tagalign -go 1.19 +go 1.21.0 require ( github.com/fatih/structtag v1.2.0 diff --git a/options.go b/options.go index ddec98d..2a78592 100644 --- a/options.go +++ b/options.go @@ -2,13 +2,6 @@ package tagalign type Option func(*Helper) -// WithMode specify the mode of tagalign. -func WithMode(mode Mode) Option { - return func(h *Helper) { - h.mode = mode - } -} - // WithSort enable tags sort. // fixedOrder specify the order of tags, the other tags will be sorted by name. // Sory is disabled by default. diff --git a/tagalign.go b/tagalign.go index 4734b56..1d79b35 100644 --- a/tagalign.go +++ b/tagalign.go @@ -1,27 +1,19 @@ package tagalign import ( + "cmp" "fmt" "go/ast" "go/token" - "log" "reflect" - "sort" + "slices" "strconv" "strings" "github.com/fatih/structtag" - "golang.org/x/tools/go/analysis" ) -type Mode int - -const ( - StandaloneMode Mode = iota - GolangciLintMode -) - type Style int const ( @@ -44,11 +36,16 @@ func NewAnalyzer(options ...Option) *analysis.Analyzer { } } -func Run(pass *analysis.Pass, options ...Option) []Issue { - var issues []Issue +func Run(pass *analysis.Pass, options ...Option) { for _, f := range pass.Files { + filename := getFilename(pass.Fset, f) + if !strings.HasSuffix(filename, ".go") { + continue + } + + println(filename) + h := &Helper{ - mode: StandaloneMode, style: DefaultStyle, align: true, } @@ -63,22 +60,19 @@ func Run(pass *analysis.Pass, options ...Option) []Issue { if !h.align && !h.sort { // do nothing - return nil + return } ast.Inspect(f, func(n ast.Node) bool { h.find(pass, n) return true }) + h.Process(pass) - issues = append(issues, h.issues...) } - return issues } type Helper struct { - mode Mode - style Style align bool // whether enable tags align. @@ -87,19 +81,6 @@ type Helper struct { singleFields []*ast.Field consecutiveFieldsGroups [][]*ast.Field // fields in this group, must be consecutive in struct. - issues []Issue -} - -// Issue is used to integrate with golangci-lint's inline auto fix. -type Issue struct { - Pos token.Position - Message string - InlineFix InlineFix -} -type InlineFix struct { - StartCol int // zero-based - Length int - NewString string } func (w *Helper) find(pass *analysis.Pass, n ast.Node) { @@ -159,42 +140,28 @@ func (w *Helper) find(pass *analysis.Pass, n ast.Node) { split() } -func (w *Helper) report(pass *analysis.Pass, field *ast.Field, startCol int, msg, replaceStr string) { - if w.mode == GolangciLintMode { - iss := Issue{ - Pos: pass.Fset.Position(field.Tag.Pos()), - Message: msg, - InlineFix: InlineFix{ - StartCol: startCol, - Length: len(field.Tag.Value), - NewString: replaceStr, - }, - } - w.issues = append(w.issues, iss) - } - - if w.mode == StandaloneMode { - pass.Report(analysis.Diagnostic{ - Pos: field.Tag.Pos(), - End: field.Tag.End(), - Message: msg, - SuggestedFixes: []analysis.SuggestedFix{ - { - Message: msg, - TextEdits: []analysis.TextEdit{ - { - Pos: field.Tag.Pos(), - End: field.Tag.End(), - NewText: []byte(replaceStr), - }, +func (w *Helper) report(pass *analysis.Pass, field *ast.Field, msg, replaceStr string) { + pass.Report(analysis.Diagnostic{ + Pos: field.Tag.Pos(), + End: field.Tag.End(), + Message: msg, + SuggestedFixes: []analysis.SuggestedFix{ + { + Message: msg, + TextEdits: []analysis.TextEdit{ + { + Pos: field.Tag.Pos(), + End: field.Tag.End(), + NewText: []byte(replaceStr), }, }, }, - }) - } + }, + }) } -func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit +//nolint:gocognit,gocyclo,nestif +func (w *Helper) Process(pass *analysis.Pass) { // process grouped fields for _, fields := range w.consecutiveFieldsGroups { offsets := make([]int, len(fields)) @@ -220,7 +187,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit tag, err := strconv.Unquote(field.Tag.Value) if err != nil { // if tag value is not a valid string, report it directly - w.report(pass, field, column, errTagValueSyntax, field.Tag.Value) + w.report(pass, field, errTagValueSyntax, field.Tag.Value) fields = removeField(fields, i) continue } @@ -228,7 +195,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit tags, err := structtag.Parse(tag) if err != nil { // if tag value is not a valid struct tag, report it directly - w.report(pass, field, column, err.Error(), field.Tag.Value) + w.report(pass, field, err.Error(), field.Tag.Value) fields = removeField(fields, i) continue } @@ -241,7 +208,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit cp[i] = tag } notSortedTagsGroup = append(notSortedTagsGroup, cp) - sortBy(w.fixedTagOrder, tags) + sortTags(w.fixedTagOrder, tags) } for _, t := range tags.Tags() { addKey(t.Key) @@ -252,7 +219,7 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit } if w.sort && StrictStyle == w.style { - sortAllKeys(w.fixedTagOrder, uniqueKeys) + sortKeys(w.fixedTagOrder, uniqueKeys) maxTagNum = len(uniqueKeys) } @@ -340,27 +307,26 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit msg := "tag is not aligned, should be: " + unquoteTag - w.report(pass, field, offsets[i], msg, newTagValue) + w.report(pass, field, msg, newTagValue) } } // process single fields for _, field := range w.singleFields { - column := pass.Fset.Position(field.Tag.Pos()).Column - 1 tag, err := strconv.Unquote(field.Tag.Value) if err != nil { - w.report(pass, field, column, errTagValueSyntax, field.Tag.Value) + w.report(pass, field, errTagValueSyntax, field.Tag.Value) continue } tags, err := structtag.Parse(tag) if err != nil { - w.report(pass, field, column, err.Error(), field.Tag.Value) + w.report(pass, field, err.Error(), field.Tag.Value) continue } originalTags := append([]*structtag.Tag(nil), tags.Tags()...) if w.sort { - sortBy(w.fixedTagOrder, tags) + sortTags(w.fixedTagOrder, tags) } newTagValue := fmt.Sprintf("`%s`", tags.String()) @@ -371,85 +337,47 @@ func (w *Helper) Process(pass *analysis.Pass) { //nolint:gocognit msg := "tag is not aligned , should be: " + tags.String() - w.report(pass, field, column, msg, newTagValue) + w.report(pass, field, msg, newTagValue) } } -// Issues returns all issues found by the analyzer. -// It is used to integrate with golangci-lint. -func (w *Helper) Issues() []Issue { - log.Println("tagalign 's Issues() should only be called in golangci-lint mode") - return w.issues -} - -// sortBy sorts tags by fixed order. +// sortTags sorts tags by fixed order. // If a tag is not in the fixed order, it will be sorted by name. -func sortBy(fixedOrder []string, tags *structtag.Tags) { - // sort by fixed order - sort.Slice(tags.Tags(), func(i, j int) bool { - ti := tags.Tags()[i] - tj := tags.Tags()[j] - - oi := findIndex(fixedOrder, ti.Key) - oj := findIndex(fixedOrder, tj.Key) - - if oi == -1 && oj == -1 { - return ti.Key < tj.Key - } - - if oi == -1 { - return false - } - - if oj == -1 { - return true - } - - return oi < oj +func sortTags(fixedOrder []string, tags *structtag.Tags) { + slices.SortFunc(tags.Tags(), func(a, b *structtag.Tag) int { + return compareByFixedOrder(fixedOrder)(a.Key, b.Key) }) } -func sortAllKeys(fixedOrder []string, keys []string) { - sort.Slice(keys, func(i, j int) bool { - oi := findIndex(fixedOrder, keys[i]) - oj := findIndex(fixedOrder, keys[j]) +func sortKeys(fixedOrder []string, keys []string) { + slices.SortFunc(keys, compareByFixedOrder(fixedOrder)) +} + +func compareByFixedOrder(fixedOrder []string) func(a, b string) int { + return func(a, b string) int { + oi := slices.Index(fixedOrder, a) + oj := slices.Index(fixedOrder, b) if oi == -1 && oj == -1 { - return keys[i] < keys[j] + return strings.Compare(a, b) } if oi == -1 { - return false + return 1 } if oj == -1 { - return true + return -1 } - return oi < oj - }) -} - -func findIndex(s []string, e string) int { - for i, a := range s { - if a == e { - return i - } + return cmp.Compare(oi, oj) } - return -1 } func alignFormat(length int) string { return "%" + fmt.Sprintf("-%ds", length) } -func max(a, b int) int { - if a > b { - return a - } - return b -} - func removeField(fields []*ast.Field, index int) []*ast.Field { if index < 0 || index >= len(fields) { return fields @@ -457,3 +385,12 @@ func removeField(fields []*ast.Field, index int) []*ast.Field { return append(fields[:index], fields[index+1:]...) } + +func getFilename(fset *token.FileSet, file *ast.File) string { + filename := fset.PositionFor(file.Pos(), true).Filename + if !strings.HasSuffix(filename, ".go") { + return fset.PositionFor(file.Pos(), false).Filename + } + + return filename +} diff --git a/tagalign_test.go b/tagalign_test.go index 20d58d4..68189cf 100644 --- a/tagalign_test.go +++ b/tagalign_test.go @@ -1,7 +1,6 @@ package tagalign import ( - "path/filepath" "testing" "github.com/fatih/structtag" @@ -9,47 +8,71 @@ import ( "golang.org/x/tools/go/analysis/analysistest" ) -func Test_alignOnly(t *testing.T) { - // only align - a := NewAnalyzer() - unsort, err := filepath.Abs("testdata/align") - assert.NoError(t, err) - analysistest.Run(t, unsort, a) -} +func TestAnalyzer(t *testing.T) { + testCases := []struct { + desc string + dir string + opts []Option + }{ + { + desc: "only align", + dir: "align_only", + }, + { + desc: "sort only", + dir: "sort_only", + opts: []Option{WithAlign(false), WithSort(nil...)}, + }, + { + desc: "sort with order", + dir: "sortorder", + opts: []Option{WithAlign(false), WithSort("xml", "json", "yaml")}, + }, + { + desc: "align and sort with fixed order", + dir: "alignsortorder", + opts: []Option{WithSort("json", "yaml", "xml")}, + }, + { + desc: "strict style", + dir: "strict", + opts: []Option{WithSort("json", "yaml", "xml"), WithStrictStyle()}, + }, + { + desc: "align single field", + dir: "single_field", + }, + { + desc: "bad syntax tag", + dir: "bad_syntax_tag", + }, + } -func Test_sortOnly(t *testing.T) { - a := NewAnalyzer(WithAlign(false), WithSort(nil...)) - sort, err := filepath.Abs("testdata/sort") - assert.NoError(t, err) - analysistest.Run(t, sort, a) -} + for _, test := range testCases { + t.Run(test.desc, func(t *testing.T) { + a := NewAnalyzer(test.opts...) -func Test_sortWithOrder(t *testing.T) { - // test disable align but enable sort - a := NewAnalyzer(WithAlign(false), WithSort("xml", "json", "yaml")) - sort, err := filepath.Abs("testdata/sortorder") - assert.NoError(t, err) - analysistest.Run(t, sort, a) + analysistest.RunWithSuggestedFixes(t, analysistest.TestData(), a, test.dir) + }) + } } -func Test_alignAndSortWithOrder(t *testing.T) { - // align and sort with fixed order - a := NewAnalyzer(WithSort("json", "yaml", "xml")) - sort, err := filepath.Abs("testdata/alignsortorder") - assert.NoError(t, err) - analysistest.Run(t, sort, a) +func TestAnalyzer_cgo(t *testing.T) { + a := NewAnalyzer() + + analysistest.Run(t, analysistest.TestData(), a, "cgo") } -func TestSprintf(t *testing.T) { +func Test_alignFormat(t *testing.T) { format := alignFormat(20) assert.Equal(t, "%-20s", format) } -func Test_sortBy(t *testing.T) { +func Test_sortTags(t *testing.T) { tags, err := structtag.Parse(`zip:"foo" json:"foo,omitempty" yaml:"bar" binding:"required" xml:"baz" gorm:"column:foo"`) assert.NoError(t, err) - sortBy([]string{"json", "yaml", "xml"}, tags) + sortTags([]string{"json", "yaml", "xml"}, tags) assert.Equal(t, "json", tags.Tags()[0].Key) assert.Equal(t, "yaml", tags.Tags()[1].Key) assert.Equal(t, "xml", tags.Tags()[2].Key) @@ -57,27 +80,3 @@ func Test_sortBy(t *testing.T) { assert.Equal(t, "gorm", tags.Tags()[4].Key) assert.Equal(t, "zip", tags.Tags()[5].Key) } - -func Test_strictStyle(t *testing.T) { - // align and sort with fixed order - a := NewAnalyzer(WithSort("json", "yaml", "xml"), WithStrictStyle()) - sort, err := filepath.Abs("testdata/strict") - assert.NoError(t, err) - analysistest.Run(t, sort, a) -} - -func Test_alignSingleField(t *testing.T) { - // only align - a := NewAnalyzer() - unsort, err := filepath.Abs("testdata/single_field") - assert.NoError(t, err) - analysistest.Run(t, unsort, a) -} - -func Test_badSyntaxTag(t *testing.T) { - // only align - a := NewAnalyzer() - unsort, err := filepath.Abs("testdata/bad_syntax_tag") - assert.NoError(t, err) - analysistest.Run(t, unsort, a) -} diff --git a/testdata/align/example.go b/testdata/src/align_only/example.go similarity index 100% rename from testdata/align/example.go rename to testdata/src/align_only/example.go diff --git a/testdata/src/align_only/example.go.golden b/testdata/src/align_only/example.go.golden new file mode 100644 index 0000000..9df290e --- /dev/null +++ b/testdata/src/align_only/example.go.golden @@ -0,0 +1,23 @@ +package testdata + +type FooBar struct { + Foo int `json:"foo" validate:"required"` // want `tag is not aligned, should be: json:"foo"` + Bar string `json:"___bar___,omitempty" validate:"required"` // want `json:"___bar___,omitempty" validate:"required"` + FooFoo int8 `json:"foo_foo" validate:"required" yaml:"fooFoo"` // want `tag is not aligned, should be: json:"foo_foo"` + BarBar int `json:"bar_bar" validate:"required"` // want `tag is not aligned, should be: json:"bar_bar"` + FooBar struct { + Foo int `json:"foo" yaml:"foo" validate:"required"` // want `tag is not aligned, should be: json:"foo" yaml:"foo" validate:"required"` + Bar222 string `json:"bar222" validate:"required" yaml:"bar"` // want `tag is not aligned, should be: json:"bar222" validate:"required" yaml:"bar"` + } `json:"foo_bar" validate:"required"` + FooFooFoo struct { + BarBarBar struct { + BarBarBarBar string `json:"bar_bar_bar_bar" validate:"required"` // want `json:"bar_bar_bar_bar" validate:"required"` + BarBarBarFooBar string `json:"bar_bar_bar_foo_bar" yaml:"bar" validate:"required"` // want `tag is not aligned, should be: json:"bar_bar_bar_foo_bar" yaml:"bar" validate:"required"` + } `json:"bar_bar_bar" validate:"required"` + } + BarFooBarFoo struct{} + // test comment + // test commnet 2 + BarFoo string `json:"bar_foo" validate:"required"` // want `tag is not aligned, should be: json:"bar_foo" validate:"required"` + BarFooBar string `json:"bar_foo_bar" validate:"required"` +} diff --git a/testdata/alignsortorder/example.go b/testdata/src/alignsortorder/example.go similarity index 100% rename from testdata/alignsortorder/example.go rename to testdata/src/alignsortorder/example.go diff --git a/testdata/src/alignsortorder/example.go.golden b/testdata/src/alignsortorder/example.go.golden new file mode 100644 index 0000000..ce63da0 --- /dev/null +++ b/testdata/src/alignsortorder/example.go.golden @@ -0,0 +1,13 @@ +package alignsortorder + +type AlignAndSortWithOrderExample struct { + Foo int `json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` // want `tag is not aligned, should be: json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` + Bar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` + FooBar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` + } + +type AlignAndSortWithOrderExample2 struct { + Foo int `json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` // want `tag is not aligned , should be: json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` + + Bar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned , should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` +} diff --git a/testdata/bad_syntax_tag/example.go b/testdata/src/bad_syntax_tag/example.go similarity index 100% rename from testdata/bad_syntax_tag/example.go rename to testdata/src/bad_syntax_tag/example.go diff --git a/testdata/src/bad_syntax_tag/example.go.golden b/testdata/src/bad_syntax_tag/example.go.golden new file mode 100644 index 0000000..1422449 --- /dev/null +++ b/testdata/src/bad_syntax_tag/example.go.golden @@ -0,0 +1,17 @@ +package issues6 + +type FooBar struct { + Foo int `json: "foo" validate:"required"` // want `bad syntax for struct tag value` + Bar string `json:bar` // want `bad syntax for struct tag value` + FooFoo int8 `json:"foo_foo" validate:"required"` + BarBar int `json:"bar_bar" validate:"required"` +} + +type FooBar2 struct { + Foo int `json:"foo" validate:"required"` + + FooFoo int8 `json:"foo_foo"` + BarBar int `json:"bar_bar" validate:"required"` + XXX int `json:"xxx" validate:"required"` + Bar string `json:bar` // want `bad syntax for struct tag value` +} diff --git a/testdata/src/cgo/cgo.go b/testdata/src/cgo/cgo.go new file mode 100644 index 0000000..a929e26 --- /dev/null +++ b/testdata/src/cgo/cgo.go @@ -0,0 +1,43 @@ +package cgo + +/* + #include + #include + + void myprint(char* s) { + printf("%d\n", s); + } +*/ +import "C" + +import ( + "unsafe" +) + +func _() { + cs := C.CString("Hello from stdio\n") + C.myprint(cs) + C.free(unsafe.Pointer(cs)) +} + +type FooBar struct { + Foo int `json:"foo" validate:"required"` // want `tag is not aligned, should be: json:"foo"` + Bar string `json:"___bar___,omitempty" validate:"required"` // want `json:"___bar___,omitempty" validate:"required"` + FooFoo int8 `json:"foo_foo" validate:"required" yaml:"fooFoo"` // want `tag is not aligned, should be: json:"foo_foo"` + BarBar int `json:"bar_bar" validate:"required"` // want `tag is not aligned, should be: json:"bar_bar"` + FooBar struct { + Foo int `json:"foo" yaml:"foo" validate:"required"` // want `tag is not aligned, should be: json:"foo" yaml:"foo" validate:"required"` + Bar222 string `json:"bar222" validate:"required" yaml:"bar"` // want `tag is not aligned, should be: json:"bar222" validate:"required" yaml:"bar"` + } `json:"foo_bar" validate:"required"` + FooFooFoo struct { + BarBarBar struct { + BarBarBarBar string `json:"bar_bar_bar_bar" validate:"required"` // want `json:"bar_bar_bar_bar" validate:"required"` + BarBarBarFooBar string `json:"bar_bar_bar_foo_bar" yaml:"bar" validate:"required"` // want `tag is not aligned, should be: json:"bar_bar_bar_foo_bar" yaml:"bar" validate:"required"` + } `json:"bar_bar_bar" validate:"required"` + } + BarFooBarFoo struct{} + // test comment + // test commnet 2 + BarFoo string `json:"bar_foo" validate:"required"` // want `tag is not aligned, should be: json:"bar_foo" validate:"required"` + BarFooBar string `json:"bar_foo_bar" validate:"required"` +} diff --git a/testdata/single_field/example.go b/testdata/src/single_field/example.go similarity index 100% rename from testdata/single_field/example.go rename to testdata/src/single_field/example.go diff --git a/testdata/src/single_field/example.go.golden b/testdata/src/single_field/example.go.golden new file mode 100644 index 0000000..ec31e08 --- /dev/null +++ b/testdata/src/single_field/example.go.golden @@ -0,0 +1,10 @@ +package singlefield + +type FooBar struct { + Foo int `json:"foo" validate:"required"` + Bar string `json:"bar" validate:"required"` + + FooFoo int8 `json:"foo_foo" validate:"required"` // want `json:"foo_foo" validate:"required"` + + BarBar int `json:"bar_bar" validate:"required"` +} diff --git a/testdata/sort/example.go b/testdata/src/sort_only/example.go similarity index 97% rename from testdata/sort/example.go rename to testdata/src/sort_only/example.go index d298a14..cb82133 100644 --- a/testdata/sort/example.go +++ b/testdata/src/sort_only/example.go @@ -1,4 +1,4 @@ -package sort +package sort_only import "time" diff --git a/testdata/src/sort_only/example.go.golden b/testdata/src/sort_only/example.go.golden new file mode 100644 index 0000000..d30bb5b --- /dev/null +++ b/testdata/src/sort_only/example.go.golden @@ -0,0 +1,13 @@ +package sort_only + +import "time" + +type TagAlignExampleSortOnlyKO struct { + Foo time.Time `gorm:"column:foo" json:"foo,omitempty" validate:"required" xml:"foo" yaml:"foo" zip:"foo"` // want `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"` // 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"` +} diff --git a/testdata/sortorder/example.go b/testdata/src/sortorder/example.go similarity index 100% rename from testdata/sortorder/example.go rename to testdata/src/sortorder/example.go diff --git a/testdata/src/sortorder/example.go.golden b/testdata/src/sortorder/example.go.golden new file mode 100644 index 0000000..ce9d699 --- /dev/null +++ b/testdata/src/sortorder/example.go.golden @@ -0,0 +1,12 @@ +package sortorder + +type SortWithOrderExample struct { + // not aligned but sorted, should not be reported + Foo int `xml:"baz" json:"foo,omitempty" yaml:"bar" binding:"required" gorm:"column:foo" validate:"required" zip:"foo" ` + Bar int `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" validate:"required" zip:"bar" ` + FooBar int `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" ` + // aligned but not sorted, should be reported + BarFoo int `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" validate:"required" zip:"bar"` // want `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" validate:"required" zip:"bar"` + // not aligned but sorted, should trim spaces between tags + FooBarFoo int `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" validate:"required" zip:"bar"` // want `xml:"bar" json:"bar,omitempty" yaml:"foo" gorm:"column:bar" validate:"required" zip:"bar"` +} diff --git a/testdata/strict/example.go b/testdata/src/strict/example.go similarity index 100% rename from testdata/strict/example.go rename to testdata/src/strict/example.go diff --git a/testdata/src/strict/example.go.golden b/testdata/src/strict/example.go.golden new file mode 100644 index 0000000..6cbb615 --- /dev/null +++ b/testdata/src/strict/example.go.golden @@ -0,0 +1,18 @@ +package strict + +type AlignAndSortWithOrderExample struct { + Foo int `json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` // want `tag is not aligned, should be: json:"foo,omitempty" yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` + Bar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` + FooBar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` +} + +type AlignAndSortWithOrderExample2 struct { + Foo int ` yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` // want `tag is not aligned, should be: yaml:"bar" xml:"baz" binding:"required" gorm:"column:foo" validate:"required" zip:"foo"` + Bar int `json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"bar" binding:"required" gorm:"column:bar" validate:"required"` +} + +type AlignAndSortWithOrderExample3 struct { + Foo int ` gorm:"column:foo" zip:"foo"` // want `tag is not aligned, should be: gorm:"column:foo" zip:"foo"` + Bar int `json:"bar,omitempty" yaml:"foo" xml:"barxxxxxxxxxxxx" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" xml:"barxxxxxxxxxxxx" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` + FooBar int `json:"bar,omitempty" yaml:"foo" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` // want `tag is not aligned, should be: json:"bar,omitempty" yaml:"foo" binding:"required" gorm:"column:bar" validate:"required" zip:"bar"` +}