From 128b480f444278d5ecb9bf5cd9bb73e7cfb06083 Mon Sep 17 00:00:00 2001 From: Horacio Duran Date: Thu, 22 Oct 2020 02:15:23 -0300 Subject: [PATCH] New Add/Remove prefix option (#69) * New Add/Remove prefix option Some libraries like [the gorm ORM](https://github.com/go-gorm/gorm) or the [gaum SQL query builder](https://github.com/shiftleftsecurity/gaum) use a prefix in the tag name (ie `gorm:"column:struct_field"`, gaum:"field_name=struct_field") to help ther Scanner/Valuer interact with the sql library in go. This PR adds the ability to add and remove said prefixes. I used these two libraries as samples in the tests files to help understand the rationale behind said feature to people reading without context, hopefully this doesn't break any project convention. * Add Readme section for prefix * Replaced prefix with format * Update main.go Accepting fatih's suggestion on flag doc Co-authored-by: Fatih Arslan * Update README.md Accepting fatih's suggestion on `format` flag Co-authored-by: Fatih Arslan * Update README.md Accepting fatih's suggestion on readme secion title Co-authored-by: Fatih Arslan * Rename formatting var to valueFormat * Rename $value to $field for clarity * Update readme too Co-authored-by: Fatih Arslan --- README.md | 21 +++++++++++++++++++++ main.go | 10 ++++++++++ main_test.go | 20 ++++++++++++++++++++ test-fixtures/struct_format.golden | 6 ++++++ test-fixtures/struct_format.input | 6 ++++++ test-fixtures/struct_format_existing.golden | 6 ++++++ test-fixtures/struct_format_existing.input | 6 ++++++ 7 files changed, 75 insertions(+) create mode 100644 test-fixtures/struct_format.golden create mode 100644 test-fixtures/struct_format.input create mode 100644 test-fixtures/struct_format_existing.golden create mode 100644 test-fixtures/struct_format_existing.input diff --git a/README.md b/README.md index 8cc6b67..f3d705b 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,27 @@ type Server struct { } ``` +### Formatting tag values + +By default a struct tag's value is transformed from a struct's field and used directly. As an example for the field `Server string`, we generate a tag in the form: `json:"server"` (assuming `-add-tags=json` is used). + +However, some third party libraries use tags in a different way and might require to them to have a particular formatting, such as is the case of prefixing them (`field_name=`). The `--format` flag allows you to specify a custom format for the tag value to be applied. + +``` +$ gomodifytags -file demo.go -struct Server -add-tags gaum -format "field_name=$field" +``` + +```go +package main + +type Server struct { + Name string `gaum:"field_name=name"` + Port int `gaum:"field_name=port"` + EnableLogs bool `gaum:"field_name=enableLogs"` + BaseDomain string `gaum:"field_name=baseDomain"` +} +``` + ### Transformations We currently support the following transformations: diff --git a/main.go b/main.go index 4585c31..a442060 100644 --- a/main.go +++ b/main.go @@ -66,6 +66,7 @@ type config struct { transform string sort bool + valueFormat string clear bool clearOption bool } @@ -113,6 +114,10 @@ func realMain() error { flagSort = flag.Bool("sort", false, "Sort sorts the tags in increasing order according to the key name") + // formatting + flagFormatting = flag.String("format", "", + "Format the given tag's value. i.e: \"column:$field\", \"field_name=$field\"") + // option flags flagRemoveOptions = flag.String("remove-options", "", "Remove the comma separated list of options from the given keys, "+ @@ -146,6 +151,7 @@ func realMain() error { clearOption: *flagClearOptions, transform: *flagTransform, sort: *flagSort, + valueFormat: *flagFormatting, override: *flagOverride, skipUnexportedFields: *flagSkipPrivateFields, } @@ -399,6 +405,10 @@ func (c *config) addTags(fieldName string, tags *structtag.Tags) (*structtag.Tag unknown = true } + if c.valueFormat != "" { + name = strings.ReplaceAll(c.valueFormat, "$field", name) + } + for _, key := range c.add { splitted = strings.SplitN(key, ":", 2) if len(splitted) >= 2 { diff --git a/main_test.go b/main_test.go index 827ec20..63b1df6 100644 --- a/main_test.go +++ b/main_test.go @@ -41,6 +41,26 @@ func TestRewrite(t *testing.T) { transform: "snakecase", }, }, + { + file: "struct_format", + cfg: &config{ + add: []string{"gaum"}, + output: "source", + structName: "foo", + transform: "snakecase", + valueFormat: "field_name=$field", + }, + }, + { + file: "struct_format_existing", + cfg: &config{ + add: []string{"gaum"}, + output: "source", + structName: "foo", + transform: "snakecase", + valueFormat: "field_name=$field", + }, + }, { file: "struct_remove", cfg: &config{ diff --git a/test-fixtures/struct_format.golden b/test-fixtures/struct_format.golden new file mode 100644 index 0000000..ce81d1c --- /dev/null +++ b/test-fixtures/struct_format.golden @@ -0,0 +1,6 @@ +package foo + +type foo struct { + bar string `gaum:"field_name=bar"` + t bool `gaum:"field_name=t"` +} diff --git a/test-fixtures/struct_format.input b/test-fixtures/struct_format.input new file mode 100644 index 0000000..f1c15e6 --- /dev/null +++ b/test-fixtures/struct_format.input @@ -0,0 +1,6 @@ +package foo + +type foo struct { + bar string + t bool +} diff --git a/test-fixtures/struct_format_existing.golden b/test-fixtures/struct_format_existing.golden new file mode 100644 index 0000000..577b30f --- /dev/null +++ b/test-fixtures/struct_format_existing.golden @@ -0,0 +1,6 @@ +package foo + +type foo struct { + bar string `gaum:"field_name=bar"` + timestamp time.Time `gaum:"@timestamp"` +} diff --git a/test-fixtures/struct_format_existing.input b/test-fixtures/struct_format_existing.input new file mode 100644 index 0000000..c66a65f --- /dev/null +++ b/test-fixtures/struct_format_existing.input @@ -0,0 +1,6 @@ +package foo + +type foo struct { + bar string + timestamp time.Time `gaum:"@timestamp"` +}