Skip to content

Commit

Permalink
feat: support toml (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
tmzane authored Nov 26, 2022
1 parent 1831213 commit 9b5b3b2
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 14 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ The rational from [Uber Style Guide][1]:
* `encoding/json` support
* `encoding/xml` support
* `gopkg.in/yaml.v3` support
* `github.com/BurntSushi/toml` support

## 📦 Install

Expand All @@ -46,6 +47,10 @@ go install github.com/junk1tm/musttag/cmd/musttag

## 📋 Usage

```shell
musttag ./...
```

With `go vet`:

```shell
Expand All @@ -54,7 +59,6 @@ go vet -vettool=$(which musttag) ./...

## 📅 Roadmap

* Support `toml`
* Support `mapstructure`
* Support custom tags via config

Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/junk1tm/musttag
go 1.18

require (
github.com/BurntSushi/toml v1.2.1
golang.org/x/tools v0.3.0
gopkg.in/yaml.v3 v3.0.1
)
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA=
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
Expand Down
15 changes: 15 additions & 0 deletions musttag.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (

// we need these dependencies for the tests in testdata to compile.
// `go mod tidy` will remove them from go.mod if we don't import them here.
_ "github.com/BurntSushi/toml"
_ "gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -84,6 +85,7 @@ func tagAndExpr(pass *analysis.Pass, call *ast.CallExpr) (string, ast.Expr, bool
jsonTag = "json"
xmlTag = "xml"
yamlTag = "yaml"
tomlTag = "toml"
)

fn := typeutil.StaticCallee(pass.TypesInfo, call)
Expand All @@ -99,6 +101,7 @@ func tagAndExpr(pass *analysis.Pass, call *ast.CallExpr) (string, ast.Expr, bool
return jsonTag, call.Args[0], true
case "encoding/json.Unmarshal":
return jsonTag, call.Args[1], true

case "encoding/xml.Marshal",
"encoding/xml.MarshalIndent",
"(*encoding/xml.Encoder).Encode",
Expand All @@ -108,12 +111,24 @@ func tagAndExpr(pass *analysis.Pass, call *ast.CallExpr) (string, ast.Expr, bool
return xmlTag, call.Args[0], true
case "encoding/xml.Unmarshal":
return xmlTag, call.Args[1], true

case "gopkg.in/yaml.v3.Marshal",
"(*gopkg.in/yaml.v3.Encoder).Encode",
"(*gopkg.in/yaml.v3.Decoder).Decode":
return yamlTag, call.Args[0], true
case "gopkg.in/yaml.v3.Unmarshal":
return yamlTag, call.Args[1], true

case "(*github.com/BurntSushi/toml.Encoder).Encode",
"(*github.com/BurntSushi/toml.Decoder).Decode":
return tomlTag, call.Args[0], true
case "github.com/BurntSushi/toml.Unmarshal",
"github.com/BurntSushi/toml.Decode",
"github.com/BurntSushi/toml.DecodeFile":
return tomlTag, call.Args[1], true
case "github.com/BurntSushi/toml.DecodeFS":
return tomlTag, call.Args[2], true

default:
return "", nil, false
}
Expand Down
5 changes: 2 additions & 3 deletions musttag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package musttag
import (
"go/ast"
"go/token"
"path"
"strings"
"testing"

Expand Down Expand Up @@ -44,7 +45,5 @@ func shortName(name string) string {
name = strings.ReplaceAll(name, "*", "")
name = strings.ReplaceAll(name, "(", "")
name = strings.ReplaceAll(name, ")", "")
name = strings.TrimPrefix(name, "encoding/")
name = strings.TrimPrefix(name, "gopkg.in/")
return name
return path.Base(name)
}
10 changes: 10 additions & 0 deletions testdata/src/examples/examples.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"encoding/xml"

"github.com/BurntSushi/toml"
"gopkg.in/yaml.v3"
)

Expand Down Expand Up @@ -35,3 +36,12 @@ func exampleYAML() {
yaml.Marshal(user)
yaml.Unmarshal(nil, &user)
}

func exampleTOML() {
var user struct { // want `\Qexported fields should be annotated with the "toml" tag`
Name string
Email string `toml:"email"`
}
toml.Decode("", &user)
toml.Unmarshal(nil, &user)
}
25 changes: 25 additions & 0 deletions testdata/src/github.com/BurntSushi/toml/toml.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Package toml provides stubs for github.com/BurntSushi/toml.
package toml

import (
"io"
"io/fs"
)

func Unmarshal(_ []byte, _ any) error { return nil }

type MetaData struct{}

func Decode(_ string, _ any) (MetaData, error) { return MetaData{}, nil }
func DecodeFS(_ fs.FS, _ string, _ any) (MetaData, error) { return MetaData{}, nil }
func DecodeFile(_ string, _ any) (MetaData, error) { return MetaData{}, nil }

type Encoder struct{}

func NewEncoder(_ io.Writer) *Encoder { return nil }
func (*Encoder) Encode(_ any) error { return nil }

type Decoder struct{}

func NewDecoder(_ io.Reader) *Decoder { return nil }
func (*Decoder) Decode(_ any) error { return nil }
2 changes: 1 addition & 1 deletion testdata/src/gopkg.in/yaml.v3/yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ func Unmarshal(_ []byte, _ any) error { return nil }

type Encoder struct{}

func NewEncoder(w io.Writer) *Encoder { return nil }
func NewEncoder(_ io.Writer) *Encoder { return nil }
func (*Encoder) Encode(_ any) error { return nil }

type Decoder struct{}
Expand Down
88 changes: 79 additions & 9 deletions testdata/src/tests/tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"encoding/xml"

"github.com/BurntSushi/toml"
"gopkg.in/yaml.v3"
)

Expand All @@ -28,7 +29,14 @@ func namedType() {
`\Qyaml.v3.Marshal`
`\Qyaml.v3.Unmarshal`
`\Qyaml.v3.Encoder.Encode`
`\Qyaml.v3.Decoder.Decode` */
`\Qyaml.v3.Decoder.Decode`
`\Qtoml.Unmarshal`
`\Qtoml.Decode`
`\Qtoml.DecodeFS`
`\Qtoml.DecodeFile`
`\Qtoml.Encoder.Encode`
`\Qtoml.Decoder.Decode` */
NoTag int
}
var x X
Expand All @@ -51,6 +59,13 @@ func namedType() {
yaml.Unmarshal(nil, &x)
yaml.NewEncoder(nil).Encode(X{})
yaml.NewDecoder(nil).Decode(&X{})

toml.Unmarshal(nil, &x)
toml.Decode("", &x)
toml.DecodeFS(nil, "", &x)
toml.DecodeFile("", &x)
toml.NewEncoder(nil).Encode(X{})
toml.NewDecoder(nil).Decode(&X{})
}

func nestedNamedType() {
Expand All @@ -72,11 +87,18 @@ func nestedNamedType() {
`\Qyaml.v3.Marshal`
`\Qyaml.v3.Unmarshal`
`\Qyaml.v3.Encoder.Encode`
`\Qyaml.v3.Decoder.Decode` */
`\Qyaml.v3.Decoder.Decode`
`\Qtoml.Unmarshal`
`\Qtoml.Decode`
`\Qtoml.DecodeFS`
`\Qtoml.DecodeFile`
`\Qtoml.Encoder.Encode`
`\Qtoml.Decoder.Decode` */
NoTag int
}
type X struct {
Y Y `json:"y" xml:"Y" yaml:"y"`
Y Y `json:"y" xml:"y" yaml:"y" toml:"y"`
}
var x X

Expand All @@ -98,6 +120,13 @@ func nestedNamedType() {
yaml.Unmarshal(nil, &x)
yaml.NewEncoder(nil).Encode(X{})
yaml.NewDecoder(nil).Decode(&X{})

toml.Unmarshal(nil, &x)
toml.Decode("", &x)
toml.DecodeFS(nil, "", &x)
toml.DecodeFile("", &x)
toml.NewEncoder(nil).Encode(X{})
toml.NewDecoder(nil).Decode(&X{})
}

func anonymousType() {
Expand All @@ -111,7 +140,12 @@ func anonymousType() {
`\Qxml.Unmarshal`
`\Qyaml.v3.Marshal`
`\Qyaml.v3.Unmarshal` */
`\Qyaml.v3.Unmarshal`
`\Qtoml.Unmarshal`
`\Qtoml.Decode`
`\Qtoml.DecodeFS`
`\Qtoml.DecodeFile` */
NoTag int
}

Expand All @@ -133,6 +167,13 @@ func anonymousType() {
yaml.Unmarshal(nil, &x)
yaml.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qyaml.v3.Encoder.Encode`
yaml.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qyaml.v3.Decoder.Decode`

toml.Unmarshal(nil, &x)
toml.Decode("", &x)
toml.DecodeFS(nil, "", &x)
toml.DecodeFile("", &x)
toml.NewEncoder(nil).Encode(struct{ NoTag int }{}) // want `\Qtoml.Encoder.Encode`
toml.NewDecoder(nil).Decode(&struct{ NoTag int }{}) // want `\Qtoml.Decoder.Decode`
}

func nestedAnonymousType() {
Expand All @@ -146,8 +187,13 @@ func nestedAnonymousType() {
`\Qxml.Unmarshal`
`\Qyaml.v3.Marshal`
`\Qyaml.v3.Unmarshal` */
Y *struct{ NoTag int } `json:"y"`
`\Qyaml.v3.Unmarshal`
`\Qtoml.Unmarshal`
`\Qtoml.Decode`
`\Qtoml.DecodeFS`
`\Qtoml.DecodeFile` */
Y *struct{ NoTag int } `json:"y" xml:"y" yaml:"y" toml:"y"`
}

json.Marshal(x)
Expand All @@ -168,14 +214,21 @@ func nestedAnonymousType() {
yaml.Unmarshal(nil, &x)
yaml.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qyaml.v3.Encoder.Encode`
yaml.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qyaml.v3.Decoder.Decode`

toml.Unmarshal(nil, &x)
toml.Decode("", &x)
toml.DecodeFS(nil, "", &x)
toml.DecodeFile("", &x)
toml.NewEncoder(nil).Encode(struct{ Y struct{ NoTag int } }{}) // want `\Qtoml.Encoder.Encode`
toml.NewDecoder(nil).Decode(&struct{ Y struct{ NoTag int } }{}) // want `\Qtoml.Decoder.Decode`
}

// all good, nothing to report.
func typeWithAllTags() {
var x struct {
Y int `json:"y" xml:"Y" yaml:"y"`
Z int `json:"z" xml:"Z" yaml:"z"`
Nested struct{} `json:"nested" xml:"Nested" yaml:"nested"`
Y int `json:"y" xml:"y" yaml:"y" toml:"y"`
Z int `json:"z" xml:"z" yaml:"z" toml:"z"`
Nested struct{} `json:"nested" xml:"nested" yaml:"nested" toml:"nested"`
private int
}

Expand All @@ -197,6 +250,13 @@ func typeWithAllTags() {
yaml.Unmarshal(nil, &x)
yaml.NewEncoder(nil).Encode(x)
yaml.NewDecoder(nil).Decode(&x)

toml.Unmarshal(nil, &x)
toml.Decode("", &x)
toml.DecodeFS(nil, "", &x)
toml.DecodeFile("", &x)
toml.NewEncoder(nil).Encode(x)
toml.NewDecoder(nil).Decode(&x)
}

// non-static calls should be ignored.
Expand All @@ -213,6 +273,9 @@ func nonStaticCalls() {

marshalYAML := yaml.Marshal
marshalYAML(x)

unmarshalTOML := toml.Unmarshal
unmarshalTOML(nil, &x)
}

// non-struct argument calls should be ignored.
Expand All @@ -235,4 +298,11 @@ func nonStructArgument() {
yaml.Unmarshal(nil, &[]int{})
yaml.NewEncoder(nil).Encode(map[int]int{})
yaml.NewDecoder(nil).Decode(&map[int]int{})

toml.Unmarshal(nil, &[]int{})
toml.Decode("", &[]int{})
toml.DecodeFS(nil, "", &[]int{})
toml.DecodeFile("", &[]int{})
toml.NewEncoder(nil).Encode(map[int]int{})
toml.NewDecoder(nil).Decode(&map[int]int{})
}

0 comments on commit 9b5b3b2

Please sign in to comment.