tagfmt

command module
v1.1.9 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 20, 2021 License: MIT Imports: 21 Imported by: 0

README

tagfmt

Go Report Card Build Status codecov

Tagfmt formats struct tag within Go programs.

It uses blanks for alignment. tag must be in key:"value" pair format

tagfmt feature:

  • align field tags in part
  • fill specified tag key to field
  • sort field tags

get tagfmt

you can download from github releases

https://github.com/bigpigeon/tagfmt/releases

or go get

go get github.com/bigpigeon/tagfmt

usage

usage: tagfmt [flags] [path ...]
  -P string
        field name with inverse regular expression pattern
  -a    align with nearby field's tag (default true)
  -cpuprofile string
        write cpu profile to this file
  -d    display diffs instead of rewriting files
  -e    report all errors (not just the first 10 on different lines)
  -f string
        fill key and value for field e.g json=lower(_val)|yaml=snake(_val)
  -l    list files whose formatting differs from tagfmt's
  -p string
        field name with regular expression pattern (default ".*")
  -s    sort struct tag by key
  -sP string
        struct name with inverse regular expression pattern
  -so string
        sort struct tag keys order e.g json|yaml|desc
  -sp string
        struct name with regular expression pattern (default ".*")
  -sw string
        sort struct tag keys weight e.g json=1|yaml=2|desc=-1 the higher weight, the higher the ranking, default keys weight is 0
  -w    write result to (source) file instead of stdout

use in vscode

  1. install filewatcher extension first
  2. edit filewatcher settings
  3. add sub item to filewatcher.commands, and then save it
  4. open the go file, add struct field and then save it
{
   "match": "\\.go",
   "isAsync": true,
   "event": "onFileChange",
   "cmd": "tagfmt -w -f \"json=or(:tag,snake(:field))|yaml=or(:tag,lower_camel(:field))\" ${file} -s -so \"json|yaml\" ${file} " 
}

use in vscode

tag align

align tag according to the longest tag's object of each column

// tagfmt .
package main
type Example struct {
	Data      string `xml:"data" yaml:"data"  json:"data"`
	OtherData string `xml:"other_data" json:"other_data:omitempty" yaml:"other_data"`
}

the result

// tagfmt 
package main

type Example struct {
	Data      string `xml:"data"       yaml:"data"                 json:"data"`
	OtherData string `xml:"other_data" json:"other_data:omitempty" yaml:"other_data"`
}

space line or no tag's field will split this rule, just like struct field align by gofmt

//tagfmt
package main
type Example struct {
	Data string `xml:"data" yaml:"data,omitempty"  json:"data"`
	OtherData string `xml:"other_data" json:"other_data" yaml:"other_data"`

    NewLineData string `xml:"new_line_data" yaml:"new_line_data" json:"new_line_data"`
    NewLineOtherData string `xml:"new_line_other_data" yaml:"new_line_other_data"  json:"new_line_other_data"`
}
// after format
package main

type Example struct {
	Data      string `xml:"data"       yaml:"data,omitempty" json:"data"`
	OtherData string `xml:"other_data" json:"other_data"     yaml:"other_data"`

	NewLineData      string `xml:"new_line_data"       yaml:"new_line_data"       json:"new_line_data"`
	NewLineOtherData string `xml:"new_line_other_data" yaml:"new_line_other_data" json:"new_line_other_data"`
}

tag fill

tag fill can fill specified key to field tag

e.g

//tagfmt -f "json=:field"

type OrderDetail struct {
	ID       string   ``
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   ``
	Address  []string ``
}
// after format
package main

type OrderDetail struct {
	ID       string   `json:"ID"`
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   `json:"callback"`
	Address  []string `json:"address"`
}

if you didn't want to change the existing tag, use 'or' function

//tagfmt -f "json=or(:tag, :field)"

type OrderDetail struct {
	ID       string   ``
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   ``
	Address  []string ``
}
// after format
package main

type OrderDetail struct {
	ID       string   `json:"ID"`
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   `json:"Callback"`
	Address  []string `json:"Address"`
}

and then I hope the tag convert to snake case style, use snake

//tagfmt -f "json=or(:tag, snake(:field))"
type OrderDetail struct {
	ID       string   ``
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   ``
	Address  []string ``
}
// after format
package main

type OrderDetail struct {
	ID       string   `json:"id"`
	UserName string   `json:"name"`
	OrderID  string   `json:"order"`
	Callback string   `json:"callback"`
	Address  []string `json:"address"`
}

final my struct tag have some extra data need to keep it is, use ':tag_extra' to get extra data and '+' to link it

//tagfmt -f "json=snake(:field)+':tag_extra'"
type OrderDetail struct {
	ID       string   ``
	UserName string   `json:",omitempty"`
	OrderID  string   `json:"order,omitempty"`
	Callback string   ``
	Address  []string ``
}
// after format
package main

type OrderDetail struct {
	ID       string   `json:"id"`
	UserName string   `json:"user_name,omitempty"`
	OrderID  string   `json:"order_id,omitempty"`
	Callback string   `json:"callback"`
	Address  []string `json:"address"`
}

fill rule have many functions and placeholders to avoid writing tags manually

function purpose
upper(s string) a-z to A-Z
lower(s string) A-Z to a-z
snake(s string) convert upper_camel/lower_camel word to snake case
upper_camel(s string) convert snake case/lower camel case to upper camel case
lower_camel(s string) convert upper camel case/snake case to lower camel case
or(s string, s string) return return first params if it's not zero,else return the second
placeholder purpose
:field replace with struct field name
:tag replace with struct field existed tag's value
:tag_basic replace with field existed tag's basic value (the value before the first ',' )
:tag_extra replace with field existed tag's extra data (the value after the first ',' )

tag fill with comment filter

use // tagfill: [key1 key2] to filter below struct requires key

//tagfmt -f "json=snake(:tag)|yaml=lower_camel(:tag)|bson=lower_camel(:tag)|toml=upper_camel(:tag)"

package main
// tagfill: toml yaml
type OrderConfig struct {
	Name     string ``
    UserName string ``
    Pay      int    ``
}
// tagfill: json bson
type OrderDetail struct {
    ID       string ``
    UserName string ``
    Pay      int    ``
}

after format

//tagfmt -f "json=snake(:tag)|yaml=lower_camel(:tag)|bson=lower_camel(:tag)|toml=upper_camel(:tag)"

package main

// tagfill: toml yaml
type OrderConfig struct {
	Name     string `toml:"" yaml:""`
	UserName string `toml:"" yaml:""`
	Pay      int    `toml:"" yaml:""`
}

// tagfill: json bson
type OrderDetail struct {
	ID       string `bson:"" json:""`
	UserName string `bson:"" json:""`
	Pay      int    `bson:"" json:""`
}

tag sort

//tagfmt -s
package main
type Example struct {
	Data string `xml:"data" yaml:"data"  json:"data"  `
}
// after format
package main

type Example struct {
	Data string `json:"data" xml:"data" yaml:"data"`
}

you can use tag sort order to custom sort order

//tagfmt -s -so "json|yaml|desc"
package main
type Example struct {
	Data string `desc:"some inuse data" yaml:"data" json:"data" `
}
// after format
package main

type Example struct {
	Data string `json:"data" yaml:"data" desc:"some inuse data"`
}

use sort weight to determine the sort order

//tagfmt -s -sw "json=2|yaml=1|toml=1|desc=-1"
package main
type Example struct {
	Data string `desc:"some inuse data" yaml:"data" toml:"data" binding:"required" json:"data" `
}
// after format
package main

type Example struct {
	Data string `json:"data" toml:"data" yaml:"data" binding:"required" desc:"some inuse data"`
}

tag select

when use -p "regex" the tagfmt only select fields that match the regular expression

you also use the -P "regex" to invert the select

//tagfmt -P "^Ignore.*$"
type OrderDetail struct {
	ID       string   `json:"id" yaml:"id"`
	UserName string   `json:"user_name" yaml:"user_name"`
	Ignore   string   `json:"-" yaml:"-"`
	OrderID  string   `json:"order_id" yaml:"order_id"`
	Callback string   `json:"callback" yaml:"callback"`
	Address  []string `json:"address" yaml:"address"`
}

type OrderDetail struct {
	ID       string   `json:"id"        yaml:"id"`
	UserName string   `json:"user_name" yaml:"user_name"`
	Ignore   string   `json:"-" yaml:"-"`
	OrderID  string   `json:"order_id" yaml:"order_id"`
	Callback string   `json:"callback" yaml:"callback"`
	Address  []string `json:"address"  yaml:"address"`
}
struct select

just like tag select, use -sp "regex" regular expression to match what struct you want

use the -sP "regex" to invert the select

Documentation

Overview

Tagfmt formats struct tag within Go programs. It uses blanks for alignment. tag must be in key:"value" pair format

usage: tagfmt [flags] [path ...]

-P string
      field name with inverse regular expression pattern
-a    align with nearby field's tag (default true)
-cpuprofile string
      write cpu profile to this file
-d    display diffs instead of rewriting files
-e    report all errors (not just the first 10 on different lines)
-f string
      fill key and value for field e.g json=lower(_val)|yaml=snake(_val)
-l    list files whose formatting differs from tagfmt's
-p string
      field name with regular expression pattern (default ".*")
-s    sort struct tag by key
-sP string
      struct name with inverse regular expression pattern
-so string
      sort struct tag keys order e.g json|yaml|desc
-sp string
      struct name with regular expression pattern (default ".*")
-w    write result to (source) file instead of stdout

Debugging support:

-cpuprofile filename
	Write cpu profile to the specified file.

Examples

struct tag format example:
//tagfmt
struct User struct {
	Name     string `json:"name" xml:"name" yaml:"name"`
	Password string `json:"password" xml:"password" yaml:"password"`
}
// after format
struct User struct {
	Name     string `json:"name"     xml:"name"     yaml:"name"    `
	Password string `json:"password" xml:"password" yaml:"password"`
}

When invoke with -s tagfmt will sort struct tags by key.

struct tag key example:
//tagfmt -s
struct User struct {
	Name     string `xml:"name" json:"name" yaml:"name"`
}
// after format
struct User struct {
	Name     string `json:"name" xml:"name" yaml:"name"`
}

When invoke with -so <order> and -s will sort struct tags by your custom <order>

//tagfmt -s -so "json|yaml|desc"
package main
type Example struct {
	Data string `desc:"some inuse data" yaml:"data" json:"data" `
}

type Example struct {
	Data string `json:"data" yaml:"data" desc:"some inuse data"`
}

When invoke with -sw <weight> and -s will sort struct tags by your custom <weight>

//tagfmt -s -sw "json=2|yaml=1|toml=1|desc=-1"
package main
type Example struct {
	Data string `desc:"some inuse data" yaml:"data" toml:"data" binding:"required" json:"data" `
}

package main

type Example struct {
	Data string `json:"data" toml:"data" yaml:"data" binding:"required" desc:"some inuse data"`
}

When invoke with -f "*" tagfmt will fill missing key and empty value in group(group split by black line or field without tag)

struct tag fill example:
//tagfmt -f "*"
type User struct {
	Name     string `json:"name"`
	Password string `xml:"password"`
	EmptyTag string
	City     string `json:"group" xml:"group"`
	State    string `gorm:"type:varchar(64)" xml:"state"`
}
// after format
type User struct {
	Name     string `json:"name"    xml:""`
	Password string `xml:"password" json:""`
	EmptyTag string
	City     string `json:"group"            xml:"group" gorm:""`
	State    string `gorm:"type:varchar(64)" xml:"state" json:""`
}

You also can only fill "json" tag key and field name as its value

    struct tag fill example:
	//tagfmt -f "json=:field"

	type Order struct {
		ID  string ``
		Tag string ``
		Fee float32 ``
	}
	// after format
	type Order struct {
		ID  string  `json:"ID"`
		Tag string  `json:"Tag"`
		Fee float32 `json:"Fee"`
	}

use `// tagfill: [key1 key2]` to filter below struct requires key

struct tag fill example:
//tagfmt -f "json=snake(:tag)|yaml=lower_camel(:tag)|bson=lower_camel(:tag)|toml=upper_camel(:tag)"

package main
// tagfill: toml yaml
type OrderConfig struct {
	Name     string ``
	UserName string ``
	Pay      int    ``
}
// tagfill: json bson
type OrderDetail struct {
	ID       string ``
	UserName string ``
	Pay      int    ``
}

//after format

package main

// tagfill: toml yaml
type OrderConfig struct {
	Name     string `toml:"" yaml:""`
	UserName string `toml:"" yaml:""`
	Pay      int    `toml:"" yaml:""`
}

// tagfill: json bson
type OrderDetail struct {
	ID       string `bson:"" json:""`
	UserName string `bson:"" json:""`
	Pay      int    `bson:"" json:""`
}

fill rule are rich and flexible here is example about fill json key and snake converted field name as its value, final keep it's origin extra tag
struct tag fill example:
//tagfmt -f "json=snake(:field)+:tag_extra"

package main
type OrderDetail struct {
	ID       string   `json:",omitempty"`
	UserName string   `json:",omitempty"`
	OrderID  string   `json:",omitempty"`
	Callback string   ``
	Address  []string ``
}
// after format
type OrderDetail struct {
	ID       string   `json:"id,omitempty"`
	UserName string   `json:"user_name,omitempty"`
	OrderID  string   `json:"order_id,omitempty"`
	Callback string   `json:"callback"`
	Address  []string `json:"address"`
}

fill rule:
	multiple key rule split with '|'
	<key>[=<function or placehold_val or string>[+ <function or placehold_val or string> ]]
	'*' is special key, it will fill missing key and empty value in group(group split by black line or field without tag)

fill rule functions:
	upper(s string) // a-z to A-Z
	lower(s string) // A-Z to a-z
	snake(s string) // convert upper_camel/lower_camel word to snake case
	upper_camel(s string) // convert snake case/lower camel case to upper camel case
	lower_camel(s string) // convert upper camel case/snake case to lower camel case
	or(s string, s string) // return return first params if it's not zero,else return the second

fill rule placehold value:
	:field // replace with struct field name
	:tag   // replace with  struct field existed tag's value
	:tag_basic // replace with field existed tag's basic value (the value before the first ',' )
	:tag_extra // replace with field existed tag's extra data (the value after the first ',' )

fill Concatenated string
	fill rule also support use '+' to concatenated string
	//tagfmt -f "json=snake(:tag_basic)+',omitempty'"

	type OrderDetail struct {
		ID       string   `json:"id"`
		UserName string   `json:"user_name"`
		OrderID  string   `json:"order_id"`
		Callback string   `json:"callback"`
		Address  []string `json:"address"`
	}

	type OrderDetail struct {
		ID       string   `json:"id,omitempty"`
		UserName string   `json:"user_name,omitempty"`
		OrderID  string   `json:"order_id,omitempty"`
		Callback string   `json:"callback,omitempty"`
		Address  []string `json:"address,omitempty"`
	}

/* * Copyright 2020 bigpigeon. All rights reserved. * Use of this source code is governed by a MIT style * license that can be found in the LICENSE file. * */

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL