Skip to content

Commit

Permalink
Add tagliatelle linter (#1906)
Browse files Browse the repository at this point in the history
  • Loading branch information
ldez committed Apr 12, 2021
1 parent 0f3f9ef commit 93df6f7
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 0 deletions.
14 changes: 14 additions & 0 deletions .golangci.example.yml
Expand Up @@ -478,6 +478,20 @@ linters-settings:
retract-allow-no-explanation: false
# Forbid the use of the `exclude` directives. Default is false.
exclude-forbidden: false
tagliatelle:
# check the struck tag name case
case:
# use the struct field name to check the name of the struct tag
use-field-name: true
rules:
# any struct tag type can be used.
# support string case: `camel`, `pascal`, `kebab`, `snake`, `goCamel`, `goPascal`, `goKebab`, `goSnake`, `upper`, `lower`
json: camel
yaml: camel
xml: camel
bson: camel
avro: snake
mapstructure: kebab

# The custom section can be used to define linter plugins to be loaded at runtime. See README doc
# for more info.
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -43,6 +43,7 @@ require (
github.com/kunwardeep/paralleltest v1.0.2
github.com/kyoh86/exportloopref v0.1.8
github.com/ldez/gomoddirectives v0.2.1
github.com/ldez/tagliatelle v0.2.0
github.com/maratori/testpackage v1.0.1
github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // v1.0
github.com/mattn/go-colorable v0.1.8
Expand Down
4 changes: 4 additions & 0 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions pkg/config/config.go
Expand Up @@ -278,6 +278,7 @@ type LintersSettings struct {
ImportAs ImportAsSettings
GoModDirectives GoModDirectivesSettings
Promlinter PromlinterSettings
Tagliatelle TagliatelleSettings

Custom map[string]CustomLinterSettings
}
Expand Down Expand Up @@ -478,6 +479,13 @@ type GoModDirectivesSettings struct {
RetractAllowNoExplanation bool `mapstructure:"retract-allow-no-explanation"`
}

type TagliatelleSettings struct {
Case struct {
Rules map[string]string
UseFieldName bool `mapstructure:"use-field-name"`
}
}

var defaultLintersSettings = LintersSettings{
Lll: LllSettings{
LineLength: 120,
Expand Down
30 changes: 30 additions & 0 deletions pkg/golinters/tagliatelle.go
@@ -0,0 +1,30 @@
package golinters

import (
"github.com/ldez/tagliatelle"
"golang.org/x/tools/go/analysis"

"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/golinters/goanalysis"
)

func NewTagliatelle(settings *config.TagliatelleSettings) *goanalysis.Linter {
cfg := tagliatelle.Config{
Rules: map[string]string{
"json": "camel",
"yaml": "camel",
},
}

if settings != nil {
for k, v := range settings.Case.Rules {
cfg.Rules[k] = v
}
cfg.UseFieldName = settings.Case.UseFieldName
}

a := tagliatelle.New(cfg)

return goanalysis.NewLinter(a.Name, a.Doc, []*analysis.Analyzer{a}, nil).
WithLoadMode(goanalysis.LoadModeSyntax)
}
7 changes: 7 additions & 0 deletions pkg/lint/lintersdb/manager.go
Expand Up @@ -112,6 +112,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
var cyclopCfg *config.Cyclop
var importAsCfg *config.ImportAsSettings
var goModDirectivesCfg *config.GoModDirectivesSettings
var tagliatelleCfg *config.TagliatelleSettings

if m.cfg != nil {
govetCfg = &m.cfg.LintersSettings.Govet
Expand All @@ -126,6 +127,7 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
cyclopCfg = &m.cfg.LintersSettings.Cyclop
importAsCfg = &m.cfg.LintersSettings.ImportAs
goModDirectivesCfg = &m.cfg.LintersSettings.GoModDirectives
tagliatelleCfg = &m.cfg.LintersSettings.Tagliatelle
}

const megacheckName = "megacheck"
Expand Down Expand Up @@ -483,6 +485,11 @@ func (m Manager) GetAllSupportedLinterConfigs() []*linter.Config {
WithSince("v1.40.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/yeya24/promlinter"),
linter.NewConfig(golinters.NewTagliatelle(tagliatelleCfg)).
WithSince("v1.40.0").
WithPresets(linter.PresetStyle).
WithURL("https://github.com/ldez/tagliatelle"),

// nolintlint must be last because it looks at the results of all the previous linters for unused nolint directives
linter.NewConfig(golinters.NewNoLintLint()).
WithSince("v1.26.0").
Expand Down
33 changes: 33 additions & 0 deletions test/testdata/tagliatelle.go
@@ -0,0 +1,33 @@
//args: -Etagliatelle
package testdata

import "time"

type TglFoo struct {
ID string `json:"ID"` // ERROR `json\(camel\): got 'ID' want 'id'`
UserID string `json:"UserID"` // ERROR `json\(camel\): got 'UserID' want 'userId'`
Name string `json:"name"`
Value time.Duration `json:"value,omitempty"`
Bar TglBar `json:"bar"`
Bur `json:"bur"`
}

type TglBar struct {
Name string `json:"-"`
Value string `json:"value"`
CommonServiceFooItem *TglBir `json:"CommonServiceItem,omitempty"` // ERROR `json\(camel\): got 'CommonServiceItem' want 'commonServiceItem'`
}

type TglBir struct {
Name string `json:"-"`
Value string `json:"value"`
ReplaceAllowList []string `mapstructure:"replace-allow-list"`
}

type Bur struct {
Name string
Value string `yaml:"Value"` // ERROR `yaml\(camel\): got 'Value' want 'value'`
More string `json:"-"`
Also string `json:",omitempty"`
ReqPerS string `avro:"req_per_s"`
}

0 comments on commit 93df6f7

Please sign in to comment.