Skip to content

Commit

Permalink
Add --template flag to provide filenames of additional templates (#53)
Browse files Browse the repository at this point in the history
* Add --template flag to provide filenames of additional templates

* Update readme

* Add globbing support to templates

* Share globbing code between --file and --template
  • Loading branch information
charlieparkes committed Apr 30, 2021
1 parent f5cbb58 commit e81b720
Show file tree
Hide file tree
Showing 9 changed files with 199 additions and 57 deletions.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@ USAGE:
go-enum [global options] [arguments...]

GLOBAL OPTIONS:
--file value, -f value The file(s) to generate enums. Use more than one flag for more files.
--noprefix Prevents the constants generated from having the Enum as a prefix. (default: false)
--lower Adds lowercase variants of the enum strings for lookup. (default: false)
--nocase Adds case insensitive parsing to the enumeration (forces lower flag). (default: false)
--marshal Adds text (and inherently json) marshalling functions. (default: false)
--sql Adds SQL database scan and value functions. (default: false)
--flag Adds golang flag functions. (default: false)
--prefix value Replaces the prefix with a user one.
--names Generates a 'Names() []string' function, and adds the possible enum values in the error response during parsing (default: false)
--nocamel Removes the snake_case to CamelCase name changing (default: false)
--ptr Adds a pointer method to get a pointer from const values (default: false)
--sqlnullint Adds a Null{{ENUM}} type for marshalling a nullable int value to sql (default: false)
--sqlnullstr Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str (default: false)
--help, -h show help (default: false)
--file value, -f value The file(s) to generate enums. Use more than one flag for more files.
--noprefix Prevents the constants generated from having the Enum as a prefix. (default: false)
--lower Adds lowercase variants of the enum strings for lookup. (default: false)
--nocase Adds case insensitive parsing to the enumeration (forces lower flag). (default: false)
--marshal Adds text (and inherently json) marshalling functions. (default: false)
--sql Adds SQL database scan and value functions. (default: false)
--flag Adds golang flag functions. (default: false)
--prefix value Replaces the prefix with a user one.
--names Generates a 'Names() []string' function, and adds the possible enum values in the error response during parsing (default: false)
--nocamel Removes the snake_case to CamelCase name changing (default: false)
--ptr Adds a pointer method to get a pointer from const values (default: false)
--sqlnullint Adds a Null{{ENUM}} type for marshalling a nullable int value to sql (default: false)
--sqlnullstr Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str (default: false)
--template value, -t value Additional template file(s) to generate enums. Use more than one flag for more files. Templates will be executed in alphabetical order.
--help, -h show help (default: false)
```
### Syntax
Expand Down
3 changes: 3 additions & 0 deletions example/user_globbed.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func Parse{{.enum.Name}}GlobbedExample() bool {
return true
}
3 changes: 3 additions & 0 deletions example/user_globbed2.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
func Parse{{.enum.Name}}GlobbedExample2() bool {
return true
}
13 changes: 13 additions & 0 deletions example/user_template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//go:generate ../bin/go-enum -f=$GOFILE -t user_template.tmpl -t *user_glob*.tmpl

package example

// OceanColor is an enumeration of ocean colors that are allowed.
/*
ENUM(
Cerulean
Blue
Green
)
*/
type OceanColor int
4 changes: 4 additions & 0 deletions example/user_template.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Additional template
func Parse{{.enum.Name}}Example() bool {
return true
}
59 changes: 59 additions & 0 deletions example/user_template_enum.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions example/user_template_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package example

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestUserTemplateColor(t *testing.T) {
assert.Equal(t, OceanColor(0), OceanColorCerulean)
assert.Equal(t, true, ParseOceanColorExample())
assert.Equal(t, true, ParseOceanColorGlobbedExample())
assert.Equal(t, true, ParseOceanColorGlobbedExample2())
}
59 changes: 40 additions & 19 deletions generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,22 @@ const (

// Generator is responsible for generating validation files for the given in a go source file.
type Generator struct {
t *template.Template
knownTemplates map[string]*template.Template
fileSet *token.FileSet
noPrefix bool
lowercaseLookup bool
caseInsensitive bool
marshal bool
sql bool
flag bool
names bool
leaveSnakeCase bool
prefix string
sqlNullInt bool
sqlNullStr bool
ptr bool
t *template.Template
knownTemplates map[string]*template.Template
userTemplateNames []string
fileSet *token.FileSet
noPrefix bool
lowercaseLookup bool
caseInsensitive bool
marshal bool
sql bool
flag bool
names bool
leaveSnakeCase bool
prefix string
sqlNullInt bool
sqlNullStr bool
ptr bool
}

// Enum holds data for a discovered enum in the parsed source
Expand All @@ -66,10 +67,11 @@ type EnumValue struct {
// templates loaded.
func NewGenerator() *Generator {
g := &Generator{
knownTemplates: make(map[string]*template.Template),
t: template.New("generator"),
fileSet: token.NewFileSet(),
noPrefix: false,
knownTemplates: make(map[string]*template.Template),
userTemplateNames: make([]string, 0),
t: template.New("generator"),
fileSet: token.NewFileSet(),
noPrefix: false,
}

funcs := sprig.TxtFuncMap()
Expand Down Expand Up @@ -163,6 +165,18 @@ func (g *Generator) WithSQLNullStr() *Generator {
return g
}

// WithTemplates is used to provide the filenames of additional templates.
func (g *Generator) WithTemplates(filenames ...string) *Generator {
for _, ut := range template.Must(g.t.ParseFiles(filenames...)).Templates() {
if _, ok := g.knownTemplates[ut.Name()]; !ok {
g.userTemplateNames = append(g.userTemplateNames, ut.Name())
}
}
g.updateTemplates()
sort.Strings(g.userTemplateNames)
return g
}

// GenerateFromFile is responsible for orchestrating the Code generation. It results in a byte array
// that can be written to any file desired. It has already had goimports run on the code before being returned.
func (g *Generator) GenerateFromFile(inputFile string) ([]byte, error) {
Expand Down Expand Up @@ -223,6 +237,13 @@ func (g *Generator) Generate(f *ast.File) ([]byte, error) {
if err != nil {
return vBuff.Bytes(), errors.WithMessage(err, fmt.Sprintf("Failed writing enum data for enum: %q", name))
}

for _, userTemplateName := range g.userTemplateNames {
err = g.t.ExecuteTemplate(vBuff, userTemplateName, data)
if err != nil {
return vBuff.Bytes(), errors.WithMessage(err, fmt.Sprintf("Failed writing enum data for enum: %q, template: %v", name, userTemplateName))
}
}
}

formatted, err := imports.Process(pkg, vBuff.Bytes(), nil)
Expand Down
72 changes: 48 additions & 24 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,20 @@ import (
)

type rootT struct {
FileNames cli.StringSlice
NoPrefix bool
Lowercase bool
NoCase bool
Marshal bool
SQL bool
Flag bool
Prefix string
Names bool
LeaveSnakeCase bool
SQLNullStr bool
SQLNullInt bool
Ptr bool
FileNames cli.StringSlice
NoPrefix bool
Lowercase bool
NoCase bool
Marshal bool
SQL bool
Flag bool
Prefix string
Names bool
LeaveSnakeCase bool
SQLNullStr bool
SQLNullInt bool
Ptr bool
TemplateFileNames cli.StringSlice
}

func main() {
Expand Down Expand Up @@ -109,6 +110,12 @@ func main() {
Usage: "Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str",
Destination: &argv.SQLNullStr,
},
&cli.StringSliceFlag{
Name: "template",
Aliases: []string{"t"},
Usage: "Additional template file(s) to generate enums. Use more than one flag for more files. Templates will be executed in alphabetical order.",
Destination: &argv.TemplateFileNames,
},
},
Action: func(ctx *cli.Context) error {
for _, fileOption := range argv.FileNames.Value() {
Expand Down Expand Up @@ -151,20 +158,21 @@ func main() {
if argv.SQLNullStr {
g.WithSQLNullStr()
}
if templates := []string(argv.TemplateFileNames.Value()); len(templates) > 0 {
for _, t := range templates {
if fn, err := globFilenames(t); err != nil {
return err
} else {
g.WithTemplates(fn...)
}
}
}

var filenames []string

// In order to maintain existing capabilities, only glob when a * is in the path.
// Leave execution on par with old method in case there are bad patterns in use that somehow
// work without the Glob method.
if strings.Contains(fileOption, "*") {
matches, err := filepath.Glob(fileOption)
if err != nil {
return fmt.Errorf("failed parsing glob filepath\nInputFile=%s\nError=%s", color.Cyan(fileOption), color.RedBg(err))
}
filenames = append(filenames, matches...)
if fn, err := globFilenames(fileOption); err != nil {
return err
} else {
filenames = append(filenames, fileOption)
filenames = fn
}

for _, fileName := range filenames {
Expand Down Expand Up @@ -203,3 +211,19 @@ func main() {
log.Fatal(err)
}
}

// globFilenames gets a list of filenames matching the provided filename.
// In order to maintain existing capabilities, only glob when a * is in the path.
// Leave execution on par with old method in case there are bad patterns in use that somehow
// work without the Glob method.
func globFilenames(filename string) ([]string, error) {
if strings.Contains(filename, "*") {
matches, err := filepath.Glob(filename)
if err != nil {
return []string{}, fmt.Errorf("failed parsing glob filepath\nInputFile=%s\nError=%s", color.Cyan(filename), color.RedBg(err))
}
return matches, nil
} else {
return []string{filename}, nil
}
}

0 comments on commit e81b720

Please sign in to comment.