diff --git a/README.md b/README.md index 736adb6..e5374c9 100644 --- a/README.md +++ b/README.md @@ -580,6 +580,28 @@ Each archive entry consists of: - the (decimal) file size, followed by a newline - the contents of the file +## Use external config file + +when we use editors like vscode to add tags, the vscode can only add json tags for us, there is no way to change the config, so I add a toml config support. +we just need add a `gomodifytags.toml` in the same directory of gomodifytags. in linux we can use `whereis gomodifytags` to get the directory. +```toml +Add = ["form", "gorm","binding"] +Transform = "camelcase" +[TemplateMap] + gorm = "column:$field" + binding = "required" +[TransformMap] + gorm = "snakecase" + +``` + +- the `Add` will add external tags to flag tag. +- the `Transform` will config transform for all tag. +- the `TemplateMap` will config template for each tag,overwrite the flag template. +- the `TransformMap` will config transform for each tag,overwrite the flag transform and Transform. + +![gomodifytags](https://user-images.githubusercontent.com/5291739/123039779-53382900-d425-11eb-9ae9-daa84f00bb23.gif) + # Development At least Go `v1.11.x` is required. Older versions might work, but it's not @@ -607,3 +629,5 @@ GO111MODULE=on go test -v -mod=vendor ``` If everything works fine, feel free to open a pull request with your changes. + + diff --git a/go.mod b/go.mod index 1a60d8e..4058e45 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,7 @@ module github.com/fatih/gomodifytags require ( + github.com/BurntSushi/toml v0.3.1 // indirect github.com/fatih/camelcase v1.0.0 github.com/fatih/structtag v1.2.0 golang.org/x/tools v0.0.0-20180824175216-6c1c5e93cdc1 diff --git a/go.sum b/go.sum index 3869a39..5e2c2e8 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= diff --git a/main.go b/main.go index e4efff7..11a9e93 100644 --- a/main.go +++ b/main.go @@ -15,11 +15,13 @@ import ( "io" "io/ioutil" "os" + "path/filepath" "sort" "strconv" "strings" "unicode" + "github.com/BurntSushi/toml" "github.com/fatih/camelcase" "github.com/fatih/structtag" "golang.org/x/tools/go/buildutil" @@ -65,11 +67,21 @@ type config struct { override bool skipUnexportedFields bool - transform string - sort bool - valueFormat string - clear bool - clearOption bool + transform string + sort bool + valueFormat string + clear bool + clearOption bool + templateMap map[string]string // give different template for each tag + transformMap map[string]string // give different transform for each tag +} + +// use toml to config the gomodifytags +type tomlConfig struct { + Add []string // add external tags + Transform string + TemplateMap map[string]string // give different template for each tag + TransformMap map[string]string // give different transform for each tag } func main() { @@ -122,6 +134,14 @@ func realMain() error { } func parseConfig(args []string) (*config, error) { + var tomlCfg tomlConfig + + ex, err := os.Executable() + if err == nil { + exPath := filepath.Dir(ex) + toml.DecodeFile(filepath.Join(exPath, "gomodifytags.toml"), &tomlCfg) + } + var ( // file flags flagFile = flag.String("file", "", "Filename to be parsed") @@ -202,12 +222,37 @@ func parseConfig(args []string) (*config, error) { skipUnexportedFields: *flagSkipUnexportedFields, } + cfg.templateMap = tomlCfg.TemplateMap + if cfg.templateMap == nil { + cfg.templateMap = make(map[string]string) + } + if tomlCfg.Transform != "" { + cfg.transform = tomlCfg.Transform + } + cfg.transformMap = tomlCfg.TransformMap + if cfg.transformMap == nil { + cfg.transformMap = make(map[string]string) + } + if *flagModified { cfg.modified = os.Stdin } + // add extenal tags config if *flagAddTags != "" { cfg.add = strings.Split(*flagAddTags, ",") + + // remove duplicate tag + addMap := make(map[string]struct{}) + for _, add := range cfg.add { + addMap[add] = struct{}{} + } + for _, add := range tomlCfg.Add { + if _, ok := addMap[add]; !ok { + cfg.add = append(cfg.add, add) + } + } + } if *flagAddOptions != "" { @@ -378,16 +423,12 @@ func (c *config) addTagOptions(tags *structtag.Tags) (*structtag.Tags, error) { return tags, nil } -func (c *config) addTags(fieldName string, tags *structtag.Tags) (*structtag.Tags, error) { - if c.add == nil || len(c.add) == 0 { - return tags, nil - } +func convertFieldName(transform, fieldName string) (name string, unknown bool) { + name = "" + unknown = false splitted := camelcase.Split(fieldName) - name := "" - - unknown := false - switch c.transform { + switch transform { case "snakecase": var lowerSplitted []string for _, s := range splitted { @@ -430,18 +471,28 @@ func (c *config) addTags(fieldName string, tags *structtag.Tags) (*structtag.Tag default: unknown = true } + return +} - if c.valueFormat != "" { - prevName := name - name = strings.ReplaceAll(c.valueFormat, "{field}", name) - if name == c.valueFormat { - // support old style for backward compatibility - name = strings.ReplaceAll(c.valueFormat, "$field", prevName) - } + +func (c *config) addTags(fieldName string, tags *structtag.Tags) (*structtag.Tags, error) { + if c.add == nil || len(c.add) == 0 { + return tags, nil } + name := fieldName + tagName := name + unknown := false + for _, key := range c.add { - splitted = strings.SplitN(key, ":", 2) + + if transform, ok := c.transformMap[key]; ok { + name, unknown = convertFieldName(transform, fieldName) + } else { + name, unknown = convertFieldName(c.transform, fieldName) + } + + splitted := strings.SplitN(key, ":", 2) if len(splitted) >= 2 { key = splitted[0] name = strings.Join(splitted[1:], "") @@ -451,16 +502,32 @@ func (c *config) addTags(fieldName string, tags *structtag.Tags) (*structtag.Tag // might pass a value return nil, fmt.Errorf("unknown transform option %q", c.transform) } + // toml template config ,overwrite the flag template + if valueFormat, ok := c.templateMap[key]; ok { + tagName = strings.ReplaceAll(valueFormat, "{field}", name) + if tagName == valueFormat { + // support old style for backward compatibility + tagName = strings.ReplaceAll(valueFormat, "$field", name) + } + } else if c.valueFormat != "" { + tagName = strings.ReplaceAll(c.valueFormat, "{field}", name) + if tagName == c.valueFormat { + // support old style for backward compatibility + tagName = strings.ReplaceAll(c.valueFormat, "$field", name) + } + } else { + tagName = name + } tag, err := tags.Get(key) if err != nil { // tag doesn't exist, create a new one tag = &structtag.Tag{ Key: key, - Name: name, + Name: tagName, } } else if c.override { - tag.Name = name + tag.Name = tagName } if err := tags.Set(tag); err != nil {