gomodifytags

1 StructTag

1
2
3
4
5
6
7
8
9
10
11
package main

import (
"fmt"
"reflect"
)

func main() {
tag := reflect.StructTag(`species:"gopher" color:"blue"`)
fmt.Println(tag.Get("color"), tag.Get("species"))
}
blue gopher
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
"fmt"

"github.com/fatih/structtag"
)

func main() {
tag := `json:"foo,omitempty,string" xml:"foo"`

// parse the tag
tags, err := structtag.Parse(string(tag))
if err != nil {
panic(err)
}

// iterate over all tags
for _, t := range tags.Tags() {
fmt.Printf("tag: %+v\n", t)
}

// get a single tag
jsonTag, err := tags.Get("json")
if err != nil {
panic(err)
}

// change existing tag
jsonTag.Name = "foo_bar"
jsonTag.Options = nil
tags.Set(jsonTag)

// add new tag
tags.Set(&structtag.Tag{
Key: "hcl",
Name: "foo",
Options: []string{"squash"},
})

// print the tags
fmt.Println(tags) // Output: json:"foo_bar" xml:"foo" hcl:"foo,squash"
}
tag: json:"foo,omitempty,string"
tag: xml:"foo"
json:"foo_bar" xml:"foo" hcl:"foo,squash"

2 AST(抽象语法树)

遍历语法树,展示结构体字段列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main

import (
"fmt"
"go/ast"
"go/parser"
"go/token"
)

func main() {
src := `package main
type Example struct {
Foo string` + " `json:\"foo\"` }"


fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "demo", src, parser.ParseComments)
if err != nil {
panic(err)
}

ast.Inspect(file, func(x ast.Node) bool {
s, ok := x.(*ast.StructType)
if !ok {
return true
}

for _, field := range s.Fields.List {
fmt.Printf("Field: %s\n", field.Names[0].Name)
fmt.Printf("Tag: %s\n", field.Tag.Value)
}
return false
})
}
Field: Foo
Tag:   `json:"foo"`

3 gomodifytags

1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string
Port int
EnableLogs bool
BaseDomain string
Credentials struct {
Username string
Password string
}
}

3.1 Struct based modification

gomodifytags -file demo.go -struct Server -add-tags json -w
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name"`
Port int `json:"port"`
EnableLogs bool `json:"enable_logs"`
BaseDomain string `json:"base_domain"`
Credentials struct {
Username string `json:"username"`
Password string `json:"password"`
} `json:"credentials"`
}

支持三种 transform , 如下所示:

  • snakecase: “BaseDomain” -> “base_domain”
  • camelcase: “BaseDomain” -> “baseDomain”
  • lispcase: “BaseDomain” -> “base-domain”
gomodifytags -file demo.go -struct Server -add-tags xml -transform camelcase
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name" xml:"name"`
Port int `json:"port" xml:"port"`
EnableLogs bool `json:"enable_logs" xml:"enableLogs"`
BaseDomain string `json:"base_domain" xml:"baseDomain"`
Credentials struct {
Username string `json:"username" xml:"username"`
Password string `json:"password" xml:"password"`
} `json:"credentials" xml:"credentials"`
}
gomodifytags -file demo.go -struct Server -add-tags xml -transform camelcase
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name" xml:"name"`
Port int `json:"port" xml:"port"`
EnableLogs bool `json:"enable_logs" xml:"enableLogs"`
BaseDomain string `json:"base_domain" xml:"baseDomain"`
Credentials struct {
Username string `json:"username" xml:"username"`
Password string `json:"password" xml:"password"`
} `json:"credentials" xml:"credentials"`
}
gomodifytags -file demo.go -struct Server -add-tags validate:gt=1,scope:read-only
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name" validate:"gt=1" scope:"read-only"`
Port int `json:"port" validate:"gt=1" scope:"read-only"`
EnableLogs bool `json:"enable_logs" validate:"gt=1" scope:"read-only"`
BaseDomain string `json:"base_domain" validate:"gt=1" scope:"read-only"`
Credentials struct {
Username string `json:"username" validate:"gt=1" scope:"read-only"`
Password string `json:"password" validate:"gt=1" scope:"read-only"`
} `json:"credentials" validate:"gt=1" scope:"read-only"`
}
gomodifytags -file demo.go -struct Server -add-tags json --add-options json=omitempty -w
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name,omitempty"`
Port int `json:"port,omitempty"`
EnableLogs bool `json:"enable_logs,omitempty"`
BaseDomain string `json:"base_domain,omitempty"`
Credentials struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
} `json:"credentials,omitempty"`
}
gomodifytags -file demo.go -struct Server -remove-tags json
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string
Port int
EnableLogs bool
BaseDomain string
Credentials struct {
Username string
Password string
}
}
gomodifytags -file demo.go -struct Server -clear-tags
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string
Port int
EnableLogs bool
BaseDomain string
Credentials struct {
Username string
Password string
}
}
gomodifytags -file demo.go -struct Server -remove-options json=omitempty
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name"`
Port int `json:"port"`
EnableLogs bool `json:"enable_logs"`
BaseDomain string `json:"base_domain"`
Credentials struct {
Username string `json:"username"`
Password string `json:"password"`
} `json:"credentials"`
}
gomodifytags -file demo.go -struct Server -clear-options
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name"`
Port int `json:"port"`
EnableLogs bool `json:"enable_logs"`
BaseDomain string `json:"base_domain"`
Credentials struct {
Username string `json:"username"`
Password string `json:"password"`
} `json:"credentials"`
}

3.2 Line based modification

gomodifytags -file demo.go -line 8,11 -clear-tags json
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name,omitempty"`
Port int `json:"port,omitempty"`
EnableLogs bool `json:"enable_logs,omitempty"`
BaseDomain string `json:"base_domain,omitempty"`
Credentials struct {
Username string
Password string
}
}
gomodifytags -file demo.go -line 6,7 -remove-tags json
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name,omitempty"`
Port int `json:"port,omitempty"`
EnableLogs bool
BaseDomain string
Credentials struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
} `json:"credentials,omitempty"`
}
gomodifytags -file demo.go -line 2,7 -add-tags bson
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name,omitempty" bson:"name"`
Port int `json:"port,omitempty" bson:"port"`
EnableLogs bool `json:"enable_logs,omitempty" bson:"enable_logs"`
BaseDomain string `json:"base_domain,omitempty" bson:"base_domain"`
Credentials struct {
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
} `json:"credentials,omitempty"`
}
gomodifytags -file demo.go -offset 100 -add-tags bson
1
2
3
4
5
6
7
8
9
10
11
12
package main

type Server struct {
Name string `json:"name,omitempty" bson:"name"`
Port int `json:"port,omitempty" bson:"port"`
EnableLogs bool `json:"enable_logs,omitempty" bson:"enable_logs"`
BaseDomain string `json:"base_domain,omitempty" bson:"base_domain"`
Credentials struct {
Username string `json:"username,omitempty" bson:"username"`
Password string `json:"password,omitempty" bson:"password"`
} `json:"credentials,omitempty" bson:"credentials"`
}

3.3 Shortcoming

1
2
3
4
5
6
7
package main

type User struct {
First_name string
Last_name string
addr string
}
gomodifytags -file user.go -struct User -add-tags json

期望得到的结果是: first_name ,但是却得到了 first___name, 同时 addr 字段不导出也生成了 tag, 如下所示:

1
2
3
4
5
6
7
package main

type User struct {
First_name string `json:"first___name"`
Last_name string `json:"last___name"`
addr string `json:"addr"`
}
Last Updated 2017-11-09 Thu 15:00.
Render by hexo-renderer-org with Emacs 25.3.2 (Org mode 8.2.10)