From d426324009c577286015d935475e42a702df17d2 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Wed, 27 Nov 2024 16:29:27 +0100 Subject: [PATCH] feat: improve pkg path option --- readme.md | 4 +- tagliatelle.go | 24 ++++--- tagliatelle_test.go | 75 +++++++++++++------- testdata/src/example.com/one-foo/b/sample.go | 56 +++++++++++++++ testdata/src/example.com/one-foo/go.mod | 3 + testdata/src/example.com/one-foo/sample.go | 56 +++++++++++++++ 6 files changed, 181 insertions(+), 37 deletions(-) create mode 100644 testdata/src/example.com/one-foo/b/sample.go create mode 100644 testdata/src/example.com/one-foo/go.mod create mode 100644 testdata/src/example.com/one-foo/sample.go diff --git a/readme.md b/readme.md index cca5a24..d3c7078 100644 --- a/readme.md +++ b/readme.md @@ -154,8 +154,8 @@ linters-settings: # Default: [] overrides: - - # The package name. (uses `/` only as separator) - # Required (but it can be explicitly an empty value to target the root package) + # The package path. (uses `/` only as separator) + # Required pkg: foo/bar # Default: empty or the same as the default/root configuration. rules: diff --git a/tagliatelle.go b/tagliatelle.go index 291ad1b..7c08eb1 100644 --- a/tagliatelle.go +++ b/tagliatelle.go @@ -68,21 +68,24 @@ func run(pass *analysis.Pass, config Config) (interface{}, error) { (*ast.StructType)(nil), } - r := createRadixTree(config, pass.Module.Path) + cfg := config.Base + if pass.Module != nil { + radixTree := createRadixTree(config, pass.Module.Path) + _, cfg, _ = radixTree.Root().LongestPrefix([]byte(pass.Pkg.Path())) + } isp.Preorder(nodeFilter, func(n ast.Node) { + if cfg.Ignore { + return + } + node, ok := n.(*ast.StructType) if !ok { return } for _, field := range node.Fields.List { - _, v, _ := r.Root().LongestPrefix([]byte(path.Join(pass.Pkg.Path(), filepath.Base(pass.Fset.File(node.Pos()).Name())))) - if v.Ignore { - continue - } - - analyze(pass, v, node, field) + analyze(pass, cfg, node, field) } }) @@ -279,7 +282,12 @@ func createRadixTree(config Config, modPath string) *iradix.Tree[Base] { c.Rules[k] = v } - r, _, _ = r.Insert([]byte(path.Join(modPath, override.Package)), c) + key := path.Join(modPath, override.Package) + if filepath.Base(modPath) == override.Package { + key = modPath + } + + r, _, _ = r.Insert([]byte(key), c) } return r diff --git a/tagliatelle_test.go b/tagliatelle_test.go index 7806e87..a1a5e97 100644 --- a/tagliatelle_test.go +++ b/tagliatelle_test.go @@ -39,6 +39,33 @@ func TestAnalyzer(t *testing.T) { }, }, }, + { + desc: "module name with hyphen", + dir: "one-foo", + patterns: []string{"example.com/fake/one-foo/..."}, + cfg: tagliatelle.Config{ + Base: tagliatelle.Base{ + Rules: map[string]string{}, + }, + Overrides: []tagliatelle.Overrides{{ + Package: "one-foo", + Base: tagliatelle.Base{ + UseFieldName: true, + Rules: map[string]string{ + "json": "camel", + "yaml": "camel", + "xml": "camel", + "bson": "camel", + "avro": "snake", + "mapstructure": "kebab", + "header": "header", + "envconfig": "upperSnake", + "env": "upperSnake", + }, + }, + }}, + }, + }, { desc: "with non-applicable overrides", dir: "one", @@ -58,18 +85,16 @@ func TestAnalyzer(t *testing.T) { }, UseFieldName: true, }, - Overrides: []tagliatelle.Overrides{ - { - Package: "one/b/c", - Base: tagliatelle.Base{ - Rules: map[string]string{ - "json": "upperSnake", - "yaml": "upperSnake", - }, - UseFieldName: false, + Overrides: []tagliatelle.Overrides{{ + Package: "one/b/c", + Base: tagliatelle.Base{ + Rules: map[string]string{ + "json": "upperSnake", + "yaml": "upperSnake", }, + UseFieldName: false, }, - }, + }}, }, }, { @@ -91,18 +116,16 @@ func TestAnalyzer(t *testing.T) { }, UseFieldName: true, }, - Overrides: []tagliatelle.Overrides{ - { - Package: "b", - Base: tagliatelle.Base{ - Rules: map[string]string{ - "json": "upperSnake", - "yaml": "upperSnake", - }, - UseFieldName: false, + Overrides: []tagliatelle.Overrides{{ + Package: "b", + Base: tagliatelle.Base{ + Rules: map[string]string{ + "json": "upperSnake", + "yaml": "upperSnake", }, + UseFieldName: false, }, - }, + }}, }, }, { @@ -124,14 +147,12 @@ func TestAnalyzer(t *testing.T) { }, UseFieldName: true, }, - Overrides: []tagliatelle.Overrides{ - { - Package: "b", - Base: tagliatelle.Base{ - Ignore: true, - }, + Overrides: []tagliatelle.Overrides{{ + Package: "b", + Base: tagliatelle.Base{ + Ignore: true, }, - }, + }}, }, }, } diff --git a/testdata/src/example.com/one-foo/b/sample.go b/testdata/src/example.com/one-foo/b/sample.go new file mode 100644 index 0000000..edded3f --- /dev/null +++ b/testdata/src/example.com/one-foo/b/sample.go @@ -0,0 +1,56 @@ +package b + +type Foo struct { + ID string `json:"ID"` // want `json\(camel\): got 'ID' want 'id'` + UserID string `json:"UserID"` // want `json\(camel\): got 'UserID' want 'userId'` + Name string `json:"name"` + Value string `json:"value,omitempty"` + Bar Bar `json:"bar"` + Bur `json:"bur"` + + Qiix Quux `json:",inline"` + Quux `json:",inline"` +} + +type Bar struct { + Name string `json:"-"` + Value string `json:"value"` + CommonServiceFooItem *Bir `json:"CommonServiceItem,omitempty"` // want `json\(camel\): got 'CommonServiceItem' want 'commonServiceFooItem'` +} + +type Bir struct { + Name string `json:"-"` + Value string `json:"value"` + ReplaceAllowList []string `mapstructure:"replace-allow-list"` +} + +type Bur struct { + Name string + Value string `yaml:"Value"` // want `yaml\(camel\): got 'Value' want 'value'` + More string `json:"-"` + Also string `json:",omitempty"` // want `json\(camel\): got 'Also' want 'also'` + ReqPerS string `avro:"req_per_s"` + HeaderValue string `header:"Header-Value"` + WrongHeaderValue string `header:"Header_Value"` // want `header\(header\): got 'Header_Value' want 'Wrong-Header-Value'` + EnvConfigValue string `envconfig:"ENV_CONFIG_VALUE"` + WrongEnvConfigValue string `envconfig:"env_config_value"` // want `envconfig\(upperSnake\): got 'env_config_value' want 'WRONG_ENV_CONFIG_VALUE'` + EnvValue string `env:"ENV_VALUE"` + WrongEnvValue string `env:"env_value"` // want `env\(upperSnake\): got 'env_value' want 'WRONG_ENV_VALUE'` +} + +type Quux struct { + Data []byte `json:"data"` +} + +// MessedUpTags struct is to validate the tool is not doing any validation about invalid tags. +// Please read the readme about this choice. +type MessedUpTags struct { + // an invalid tag cannot be validated. + Bad string `json:"bad` + + // a tag not supported by the rules is not validated. + Whatever string `foo:whatever` + + // a tag supported by the rule cannot be validated because foo tag breaks the whole tags block + Mixed string `json:"mixed" foo:mixed` +} diff --git a/testdata/src/example.com/one-foo/go.mod b/testdata/src/example.com/one-foo/go.mod new file mode 100644 index 0000000..dab3f73 --- /dev/null +++ b/testdata/src/example.com/one-foo/go.mod @@ -0,0 +1,3 @@ +module example.com/fake/one-foo + +go 1.22.0 diff --git a/testdata/src/example.com/one-foo/sample.go b/testdata/src/example.com/one-foo/sample.go new file mode 100644 index 0000000..98940d5 --- /dev/null +++ b/testdata/src/example.com/one-foo/sample.go @@ -0,0 +1,56 @@ +package one_foo + +type Foo struct { + ID string `json:"ID"` // want `json\(camel\): got 'ID' want 'id'` + UserID string `json:"UserID"` // want `json\(camel\): got 'UserID' want 'userId'` + Name string `json:"name"` + Value string `json:"value,omitempty"` + Bar Bar `json:"bar"` + Bur `json:"bur"` + + Qiix Quux `json:",inline"` + Quux `json:",inline"` +} + +type Bar struct { + Name string `json:"-"` + Value string `json:"value"` + CommonServiceFooItem *Bir `json:"CommonServiceItem,omitempty"` // want `json\(camel\): got 'CommonServiceItem' want 'commonServiceFooItem'` +} + +type Bir struct { + Name string `json:"-"` + Value string `json:"value"` + ReplaceAllowList []string `mapstructure:"replace-allow-list"` +} + +type Bur struct { + Name string + Value string `yaml:"Value"` // want `yaml\(camel\): got 'Value' want 'value'` + More string `json:"-"` + Also string `json:",omitempty"` // want `json\(camel\): got 'Also' want 'also'` + ReqPerS string `avro:"req_per_s"` + HeaderValue string `header:"Header-Value"` + WrongHeaderValue string `header:"Header_Value"` // want `header\(header\): got 'Header_Value' want 'Wrong-Header-Value'` + EnvConfigValue string `envconfig:"ENV_CONFIG_VALUE"` + WrongEnvConfigValue string `envconfig:"env_config_value"` // want `envconfig\(upperSnake\): got 'env_config_value' want 'WRONG_ENV_CONFIG_VALUE'` + EnvValue string `env:"ENV_VALUE"` + WrongEnvValue string `env:"env_value"` // want `env\(upperSnake\): got 'env_value' want 'WRONG_ENV_VALUE'` +} + +type Quux struct { + Data []byte `json:"data"` +} + +// MessedUpTags struct is to validate the tool is not doing any validation about invalid tags. +// Please read the readme about this choice. +type MessedUpTags struct { + // an invalid tag cannot be validated. + Bad string `json:"bad` + + // a tag not supported by the rules is not validated. + Whatever string `foo:whatever` + + // a tag supported by the rule cannot be validated because foo tag breaks the whole tags block + Mixed string `json:"mixed" foo:mixed` +}